提交 5b322833 编写于 作者: Q qiang

Merge branch 'dev' into alpha

!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e=e||self).uni=n()}(this,(function(){"use strict";try{var e={};Object.defineProperty(e,"passive",{get:function(){!0}}),window.addEventListener("test-passive",null,e)}catch(e){}var n=Object.prototype.hasOwnProperty;function t(e,t){return n.call(e,t)}var i=[],a=function(e,n){var t={options:{timestamp:+new Date},name:e,arg:n};if(window.__dcloud_weex_postMessage||window.__dcloud_weex_){if("postMessage"===e){var a={data:[n]};return window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessage(a):window.__dcloud_weex_.postMessage(JSON.stringify(a))}var o={type:"WEB_INVOKE_APPSERVICE",args:{data:t,webviewIds:i}};window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessageToService(o):window.__dcloud_weex_.postMessageToService(JSON.stringify(o))}if(!window.plus)return window.parent.postMessage({type:"WEB_INVOKE_APPSERVICE",data:t,pageId:""},"*");if(0===i.length){var r=plus.webview.currentWebview();if(!r)throw new Error("plus.webview.currentWebview() is undefined");var d=r.parent(),s="";s=d?d.id:r.id,i.push(s)}if(plus.webview.getWebviewById("__uniapp__service"))plus.webview.postMessageToUniNView({type:"WEB_INVOKE_APPSERVICE",args:{data:t,webviewIds:i}},"__uniapp__service");else{var w=JSON.stringify(t);plus.webview.getLaunchWebview().evalJS('UniPlusBridge.subscribeHandler("'.concat("WEB_INVOKE_APPSERVICE",'",').concat(w,",").concat(JSON.stringify(i),");"))}},o={navigateTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;a("navigateTo",{url:encodeURI(n)})},navigateBack:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.delta;a("navigateBack",{delta:parseInt(n)||1})},switchTab:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;a("switchTab",{url:encodeURI(n)})},reLaunch:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;a("reLaunch",{url:encodeURI(n)})},redirectTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;a("redirectTo",{url:encodeURI(n)})},getEnv:function(e){window.plus?e({plus:!0}):e({h5:!0})},postMessage:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};a("postMessage",e.data||{})}},r=/uni-app/i.test(navigator.userAgent),d=/complete|loaded|interactive/;var s=window.my&&navigator.userAgent.indexOf("AlipayClient")>-1;var w=window.swan&&window.swan.webView&&/swan/i.test(navigator.userAgent);var u=window.qq&&window.qq.miniProgram&&/QQ/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var c=window.tt&&window.tt.miniProgram&&/toutiaomicroapp/i.test(navigator.userAgent);var g=window.wx&&window.wx.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var v=window.qa&&/quickapp/i.test(navigator.userAgent);for(var p,l=function(){window.UniAppJSBridge=!0,document.dispatchEvent(new CustomEvent("UniAppJSBridgeReady",{bubbles:!0,cancelable:!0}))},_=[function(e){if(r)return window.__dcloud_weex_postMessage||window.__dcloud_weex_?document.addEventListener("DOMContentLoaded",e):window.plus&&d.test(document.readyState)?setTimeout(e,0):document.addEventListener("plusready",e),o},function(e){if(g)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.wx.miniProgram},function(e){if(u)return window.QQJSBridge&&window.QQJSBridge.invoke?setTimeout(e,0):document.addEventListener("QQJSBridgeReady",e),window.qq.miniProgram},function(e){if(s){document.addEventListener("DOMContentLoaded",e);var n=window.my;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(w)return document.addEventListener("DOMContentLoaded",e),window.swan.webView},function(e){if(c)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(v){window.QaJSBridge&&window.QaJSBridge.invoke?setTimeout(e,0):document.addEventListener("QaJSBridgeReady",e);var n=window.qa;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){return document.addEventListener("DOMContentLoaded",e),o}],f=0;f<_.length&&!(p=_[f](l));f++);p||(p={});var m="undefined"!=typeof uni?uni:{};if(!m.navigateTo)for(var E in p)t(p,E)&&(m[E]=p[E]);return m.webView=p,m}));
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e=e||self).uni=n()}(this,(function(){"use strict";try{var e={};Object.defineProperty(e,"passive",{get:function(){!0}}),window.addEventListener("test-passive",null,e)}catch(e){}var n=Object.prototype.hasOwnProperty;function t(e,t){return n.call(e,t)}var i=[],a=function(e,n){var t={options:{timestamp:+new Date},name:e,arg:n};if(window.__dcloud_weex_postMessage||window.__dcloud_weex_){if("postMessage"===e){var a={data:[n]};return window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessage(a):window.__dcloud_weex_.postMessage(JSON.stringify(a))}var o={type:"WEB_INVOKE_APPSERVICE",args:{data:t,webviewIds:i}};window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessageToService(o):window.__dcloud_weex_.postMessageToService(JSON.stringify(o))}if(!window.plus)return window.parent.postMessage({type:"WEB_INVOKE_APPSERVICE",data:t,pageId:""},"*");if(0===i.length){var r=plus.webview.currentWebview();if(!r)throw new Error("plus.webview.currentWebview() is undefined");var d=r.parent(),s="";s=d?d.id:r.id,i.push(s)}if(plus.webview.getWebviewById("__uniapp__service"))plus.webview.postMessageToUniNView({type:"WEB_INVOKE_APPSERVICE",args:{data:t,webviewIds:i}},"__uniapp__service");else{var w=JSON.stringify(t);plus.webview.getLaunchWebview().evalJS('UniPlusBridge.subscribeHandler("'.concat("WEB_INVOKE_APPSERVICE",'",').concat(w,",").concat(JSON.stringify(i),");"))}},o={navigateTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;a("navigateTo",{url:encodeURI(n)})},navigateBack:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.delta;a("navigateBack",{delta:parseInt(n)||1})},switchTab:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;a("switchTab",{url:encodeURI(n)})},reLaunch:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;a("reLaunch",{url:encodeURI(n)})},redirectTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;a("redirectTo",{url:encodeURI(n)})},getEnv:function(e){window.plus?e({plus:!0}):e({h5:!0})},postMessage:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};a("postMessage",e.data||{})}},r=/uni-app/i.test(navigator.userAgent),d=/Html5Plus/i.test(navigator.userAgent),s=/complete|loaded|interactive/;var w=window.my&&navigator.userAgent.indexOf("AlipayClient")>-1;var u=window.swan&&window.swan.webView&&/swan/i.test(navigator.userAgent);var c=window.qq&&window.qq.miniProgram&&/QQ/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var g=window.tt&&window.tt.miniProgram&&/toutiaomicroapp/i.test(navigator.userAgent);var v=window.wx&&window.wx.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var p=window.qa&&/quickapp/i.test(navigator.userAgent);for(var l,_=function(){window.UniAppJSBridge=!0,document.dispatchEvent(new CustomEvent("UniAppJSBridgeReady",{bubbles:!0,cancelable:!0}))},f=[function(e){if(r||d)return window.__dcloud_weex_postMessage||window.__dcloud_weex_?document.addEventListener("DOMContentLoaded",e):window.plus&&s.test(document.readyState)?setTimeout(e,0):document.addEventListener("plusready",e),o},function(e){if(v)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.wx.miniProgram},function(e){if(c)return window.QQJSBridge&&window.QQJSBridge.invoke?setTimeout(e,0):document.addEventListener("QQJSBridgeReady",e),window.qq.miniProgram},function(e){if(w){document.addEventListener("DOMContentLoaded",e);var n=window.my;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(u)return document.addEventListener("DOMContentLoaded",e),window.swan.webView},function(e){if(g)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(p){window.QaJSBridge&&window.QaJSBridge.invoke?setTimeout(e,0):document.addEventListener("QaJSBridgeReady",e);var n=window.qa;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){return document.addEventListener("DOMContentLoaded",e),o}],m=0;m<f.length&&!(l=f[m](_));m++);l||(l={});var E="undefined"!=typeof uni?uni:{};if(!E.navigateTo)for(var b in l)t(l,b)&&(E[b]=l[b]);return E.webView=l,E}));
const t = require('@babel/types')
const traverse = require('@babel/traverse').default
function cached (fn) {
const cache = Object.create(null)
return function cachedFn (str) {
......@@ -82,12 +85,55 @@ module.exports = {
type: 'view',
attr: {
slot: slotName
},
children: normalizeChildren(traverseExpr(returnExprNodes, state))
}
}
if (paramExprNode && paramExprNode.type === 'Identifier') {
node.scoped = paramExprNode.name
if (paramExprNode) {
if (t.isIdentifier(paramExprNode)) {
const scoped = paramExprNode.name
node.attr['slot-scope'] = scoped
} else if (t.isObjectPattern(paramExprNode)) {
const paramName = '__SCOPED__'
node.attr['slot-scope'] = paramName
const start = returnExprNodes.start
const end = returnExprNodes.end
const names = []
paramExprNode.properties.forEach(property => {
const key = property.key
const value = property.value
if (t.isIdentifier(value)) {
if (value.name !== key.name) {
state.errors.add(`解构插槽 Prop 时,不支持将${key.name}重命名为${value.name},重命名后会影响性能`)
return
}
} else if (t.isAssignmentPattern(value)) {
state.errors.add(`解构插槽 Prop 时,不支持为${key.name}设置默认值`)
return
}
names.push(key.name)
})
traverse({
type: 'Program',
start,
end,
body: [{
type: 'ExpressionStatement',
start,
end,
expression: returnExprNodes
}],
sourceType: 'module'
}, {
Identifier (path) {
const node = path.node
const name = node.name
if (names.includes(name) && path.key !== 'key' && path.key !== 'property' && !(path.scope && path.scope.hasBinding(name))) {
path.replaceWithSourceString(`${paramName}.${name}`)
}
}
})
}
}
node.children = normalizeChildren(traverseExpr(returnExprNodes, state))
return node
}
}
}
......@@ -12,9 +12,9 @@ wx.createComponent({
`
}
function generateCssCode (ownerName) {
function generateCssCode (filename) {
return `
@import './${ownerName}.wxss'
@import "./${filename}"
`
}
......@@ -32,11 +32,21 @@ module.exports = {
state.componentGenerics[componentName] = true
return {
type: componentName,
attr: props || {},
children: []
}
// 返回多个节点,支持作用域插槽当作普通插槽使用
return [
{
type: 'slot',
attr: {
name: slotName
},
children: []
},
{
type: componentName,
attr: props || {},
children: []
}
]
},
resolveScopedSlots (slotName, {
genCode,
......@@ -106,10 +116,15 @@ module.exports = {
const jsContent = generateJsCode(genCode(t.objectExpression(objectProperties), true))
state.files[jsFile] = jsContent
const cssFile = resourcePath.replace(ownerName + extname, componentName + '.wxss')
const cssContent = generateCssCode(ownerName)
try {
// TODO 使用 getPlatformExts 在单元测试报错,改从 state.options.platform 判断
const { getPlatformExts } = require('@dcloudio/uni-cli-shared')
const styleExtname = getPlatformExts().style
const styleFile = resourcePath.replace(ownerName + extname, componentName + styleExtname)
const styleContent = generateCssCode(ownerName + styleExtname)
state.files[cssFile] = cssContent
state.files[styleFile] = styleContent
} catch (error) {}
if (!state.generic) {
state.generic = []
......
......@@ -380,12 +380,9 @@ const requestData = (done) => {
if (report_status_code === '') {
report_status_code = 1
}
if (report_status_code === 1) {
typeof done === 'function' && done({
enable: res.enable
})
}
// console.error('统计请求错误');
typeof done === 'function' && done({
enable: report_status_code
})
}
});
}
......@@ -226,12 +226,12 @@ describe('mp:compiler-extra', () => {
assertCodegen(
'<component1 v-slot>text</component1>',
'<component1 vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'default\']}}"><view slot="default">text</view></component1>'
'<component1 vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'default\']}}"><view>text</view></component1>'
)
assertCodegen(
'<component1 v-slot:default>text<text>123213</text></component1>',
'<component1 vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'default\']}}"><view slot="default">text<text>123213</text></view></component1>'
'<component1 vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'default\']}}"><view>text<text>123213</text></view></component1>'
)
assertCodegen(
'<component1><template v-slot:left><text></text></template><template v-slot:right><text></text></template></component1>',
......@@ -676,4 +676,4 @@ describe('mp:compiler-extra', () => {
'<video controls></video>'
)
})
})
})
......@@ -60,6 +60,18 @@ describe('mp:compiler-mp-alipay', () => {
'<component1 vue-id="551070e6-1" onVueInit="__l">text<view slot="right"></view></component1>'
)
})
it('generate scoped slot', () => {
assertCodegen(
'<component1 :text="\'text\'"><template v-slot="props"><view :class="{text:props.text}">{{props.text}}</view></template></component1>',
'<component1 vue-id="551070e6-1" text="text" onVueInit="__l"><view slot-scope="props"><view class="{{((props.text)?\'text\':\'\')}}">{{props.text}}</view></view></component1>'
)
assertCodegen(
'<component1 :text="\'text\'"><template v-slot="{text}"><view :class="{text:text}">{{text}}</view></template></component1>',
'<component1 vue-id="551070e6-1" text="text" onVueInit="__l"><view slot-scope="__SCOPED__"><view class="{{((__SCOPED__.text)?\'text\':\'\')}}">{{__SCOPED__.text}}</view></view></component1>'
)
})
it('generate class binding', () => {
assertCodegen(
'<div :class="{ active: isActive }">1</div>',
......@@ -148,4 +160,4 @@ describe('mp:compiler-mp-alipay', () => {
'<movable-view data-event-opts="{{[[\'changeEnd\',[[\'changeEnd\',[\'$event\']]]]]}}" onChangeEnd="__e"></movable-view>'
)
})
})
})
const compiler = require('../lib')
function assertCodegen (template, templateCode, renderCode = 'with(this){}', options = {}) {
const res = compiler.compile(template, {
const res = compiler.compile(template, {
resourcePath: 'test.wxml',
mp: Object.assign({
minified: true,
......@@ -24,11 +24,11 @@ describe('mp:compiler-mp-baidu', () => {
it('generate scoped slot', () => {
assertCodegen(
'<foo><template slot-scope="bar">{{ bar.foo }}</template></foo>',
'<foo vue-id="551070e6-1" vue-slots="{{[\'default\']}}"><view slot="default">{{foo}}</view></foo>'
'<foo vue-id="551070e6-1" vue-slots="{{[\'default\']}}"><view>{{foo}}</view></foo>'
)
assertCodegen(
'<foo><view slot-scope="bar">{{ bar.foo }}</view></foo>',
'<foo vue-id="551070e6-1" vue-slots="{{[\'default\']}}"><view slot="default"><view>{{foo}}</view></view></foo>'
'<foo vue-id="551070e6-1" vue-slots="{{[\'default\']}}"><view><view>{{foo}}</view></view></foo>'
)
})
......@@ -46,7 +46,7 @@ describe('mp:compiler-mp-baidu', () => {
it('generate scoped slot with multiline v-if', () => {
assertCodegen(
'<foo><template v-if="\nshow\n" slot-scope="bar">{{ bar.foo }}</template></foo>',
'<foo vue-id="551070e6-1" vue-slots="{{[\'default\']}}"><view slot="default"><block s-if="{{show}}">{{foo}}</block><block s-else><block></block></block></view></foo>'
'<foo vue-id="551070e6-1" vue-slots="{{[\'default\']}}"><view><block s-if="{{show}}">{{foo}}</block><block s-else><block></block></block></view></foo>'
)
assertCodegen(
'<foo><view v-if="\nshow\n" slot="foo" slot-scope="bar">{{ bar.foo }}</view></foo>',
......@@ -57,54 +57,54 @@ describe('mp:compiler-mp-baidu', () => {
it('generate scoped slot', () => {
assertCodegen(
'<span><slot v-bind:user="user">{{ user.lastName }}</slot></span>',
'<label class="_span"><block s-if="{{$slots.default}}"><slot name="default" var-user="user"></slot></block><block s-else>{{user.lastName}}</block></label>'
'<label class="_span"><block s-if="{{$slots.default}}"><slot var-user="user"></slot></block><block s-else>{{user.lastName}}</block></label>'
)
assertCodegen(
'<span><slot name="header" v-bind:user="user">{{ user.lastName }}</slot></span>',
'<label class="_span"><block s-if="{{$slots.header}}"><slot name="header" var-user="user"></slot></block><block s-else>{{user.lastName}}</block></label>'
)
})
it('generate vue id', () => {
assertCodegen(
'<Test/>',
'<test vue-id="551070e6-1"></test>'
)
assertCodegen(
'<Test a="a">',
'<test vue-id="551070e6-1" a="a"></test>'
)
assertCodegen(
'<view><Test v-for="item in items" :key="item"/></view>',
'<view><block s-for="{{items}}" s-for-item="item" s-for-index="__i0__" s-key="*this"><test vue-id="{{\'551070e6-1-\'+__i0__}}"></test></block></view>'
)
assertCodegen(
'<view><Test v-for="item in items" :key="item"><Test v-for="item in item.items" :key="item"></Test></Test></view>',
'<view><block s-for="{{items}}" s-for-item="item" s-for-index="__i0__" s-key="*this"><test vue-id="{{\'551070e6-1-\'+__i0__}}" vue-slots="{{[\'default\']}}"><block s-for="{{item.items}}" s-for-item="item" s-for-index="__i1__" s-key="*this"><test vue-id="{{(\'551070e6-2-\'+__i0__+\'-\'+__i1__)+\',\'+(\'551070e6-1-\'+__i0__)}}"></test></block></test></block></view>'
)
assertCodegen(
'<view><Test v-for="(item,index) in items" :key="item"><Test v-for="(item,index1) in item.items" :key="item"></Test></Test></view>',
'<view><block s-for="{{items}}" s-for-item="item" s-for-index="index" s-key="*this"><test vue-id="{{\'551070e6-1-\'+index}}" vue-slots="{{[\'default\']}}"><block s-for="{{item.items}}" s-for-item="item" s-for-index="index1" s-key="*this"><test vue-id="{{(\'551070e6-2-\'+index+\'-\'+index1)+\',\'+(\'551070e6-1-\'+index)}}"></test></block></test></block></view>'
)
})
it('generate text trim', () => {
assertCodegen(
'<text>\nN: {{title}}\n′</text>',
'<text>{{\'N: \'+title+"\\\\n′"}}</text>'
)
assertCodegen(
'<text>我是第一行1\n我的第二行</text>',
'<text>我是第一行1\n我的第二行</text>'
)
assertCodegen(
'<text>我是第一行2\n我的第二行1{{title}}</text>',
'<text>{{"我是第一行2\\\\n我的第二行1"+title}}</text>'
)
assertCodegen(
`<text>我是第一行3
我的第二行2{{title}}</text>`,
'<text>{{"我是第一行3\\\\n 我的第二行2"+title}}</text>'
)
})
})
it('generate vue id', () => {
assertCodegen(
'<Test/>',
'<test vue-id="551070e6-1"></test>'
)
assertCodegen(
'<Test a="a">',
'<test vue-id="551070e6-1" a="a"></test>'
)
assertCodegen(
'<view><Test v-for="item in items" :key="item"/></view>',
'<view><block s-for="{{items}}" s-for-item="item" s-for-index="__i0__" s-key="*this"><test vue-id="{{\'551070e6-1-\'+__i0__}}"></test></block></view>'
)
assertCodegen(
'<view><Test v-for="item in items" :key="item"><Test v-for="item in item.items" :key="item"></Test></Test></view>',
'<view><block s-for="{{items}}" s-for-item="item" s-for-index="__i0__" s-key="*this"><test vue-id="{{\'551070e6-1-\'+__i0__}}" vue-slots="{{[\'default\']}}"><block s-for="{{item.items}}" s-for-item="item" s-for-index="__i1__" s-key="*this"><test vue-id="{{(\'551070e6-2-\'+__i0__+\'-\'+__i1__)+\',\'+(\'551070e6-1-\'+__i0__)}}"></test></block></test></block></view>'
)
assertCodegen(
'<view><Test v-for="(item,index) in items" :key="item"><Test v-for="(item,index1) in item.items" :key="item"></Test></Test></view>',
'<view><block s-for="{{items}}" s-for-item="item" s-for-index="index" s-key="*this"><test vue-id="{{\'551070e6-1-\'+index}}" vue-slots="{{[\'default\']}}"><block s-for="{{item.items}}" s-for-item="item" s-for-index="index1" s-key="*this"><test vue-id="{{(\'551070e6-2-\'+index+\'-\'+index1)+\',\'+(\'551070e6-1-\'+index)}}"></test></block></test></block></view>'
)
})
it('generate text trim', () => {
assertCodegen(
'<text>\nN: {{title}}\n′</text>',
'<text>{{\'N: \'+title+"\\\\n′"}}</text>'
)
assertCodegen(
'<text>我是第一行1\n我的第二行</text>',
'<text>我是第一行1\n我的第二行</text>'
)
assertCodegen(
'<text>我是第一行2\n我的第二行1{{title}}</text>',
'<text>{{"我是第一行2\\\\n我的第二行1"+title}}</text>'
)
assertCodegen(
`<text>我是第一行3
我的第二行2{{title}}</text>`,
'<text>{{"我是第一行3\\\\n 我的第二行2"+title}}</text>'
)
})
})
......@@ -72,16 +72,23 @@ describe('mp:compiler-mp-weixin', () => {
})
it('generate scoped slot', () => {
assertCodegen(
'<slot v-bind:user="user"></slot>',
'<slot></slot><scoped-slots-default user="{{user}}" bind:__l="__l"></scoped-slots-default>',
function (res) {
expect(res.componentGenerics['scoped-slots-default']).toBe(true)
}
)
assertCodegen( // TODO vue-id
'<span><slot v-bind:user="user">{{ user.lastName }}</slot></span>',
'<label class="_span"><block wx:if="{{$slots.default}}"><scoped-slots-default user="{{user}}" bind:__l="__l"></scoped-slots-default></block><block wx:else>{{user.lastName}}</block></label>',
'<label class="_span"><block wx:if="{{$slots.default}}"><slot></slot><scoped-slots-default user="{{user}}" bind:__l="__l"></scoped-slots-default></block><block wx:else>{{user.lastName}}</block></label>',
function (res) {
expect(res.componentGenerics['scoped-slots-default']).toBe(true)
}
)
assertCodegen(
'<span><slot name="header" v-bind:user="user">{{ user.lastName }}</slot></span>',
'<label class="_span"><block wx:if="{{$slots.header}}"><scoped-slots-header user="{{user}}" bind:__l="__l"></scoped-slots-header></block><block wx:else>{{user.lastName}}</block></label>',
'<label class="_span"><block wx:if="{{$slots.header}}"><slot name="header"></slot><scoped-slots-header user="{{user}}" bind:__l="__l"></scoped-slots-header></block><block wx:else>{{user.lastName}}</block></label>',
function (res) {
expect(res.componentGenerics['scoped-slots-header']).toBe(true)
}
......@@ -113,4 +120,4 @@ describe('mp:compiler-mp-weixin', () => {
'<view><slot-comp generic:scoped-slots-test="test-slot-comp-test" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'test\']}}"></slot-comp><slot-comp generic:scoped-slots-test="test-slot-comp-test1" vue-id="551070e6-2" bind:__l="__l" vue-slots="{{[\'test\']}}"></slot-comp><slot-comp generic:scoped-slots-test="test-slot-comp-test2" vue-id="551070e6-3" bind:__l="__l" vue-slots="{{[\'test\']}}"></slot-comp><slot-comp generic:scoped-slots-test="test-slot-comp-test3" vue-id="551070e6-4" bind:__l="__l" vue-slots="{{[\'test\']}}"></slot-comp></view>'
)
})
})
})
const compiler = require('../lib')
function assertCodegen (template, templateCode, renderCode = 'with(this){}') {
const res = compiler.compile(template, {
const res = compiler.compile(template, {
resourcePath: 'test.wxml',
mp: {
minified: true,
......@@ -172,6 +172,9 @@ describe('mp:compiler', () => {
it('generate single slot', () => {
assertCodegen('<view><slot></slot></view>', '<view><slot></slot></view>')
assertCodegen('<view><slot>default</slot></view>', '<view><block wx:if="{{$slots.default}}"><slot></slot></block><block wx:else>default</block></view>')
assertCodegen('<view><slot>{{hello}}</slot></view>', '<view><block wx:if="{{$slots.default}}"><slot></slot></block><block wx:else>{{hello}}</block></view>')
assertCodegen('<view><slot name="default"></slot></view>', '<view><slot></slot></view>')
})
it('generate named slot', () => {
......@@ -193,6 +196,10 @@ describe('mp:compiler', () => {
'<view slot="one">hello world</view>',
'<view slot="one">hello world</view>'
)
assertCodegen(
'<view slot="default">hello world</view>',
'<view>hello world</view>'
)
})
// it('generate scoped slot', () => {
......@@ -486,7 +493,7 @@ describe('mp:compiler', () => {
)
// normal named function
assertCodegen(
'<input @input="function fn () { current++ }">',
'<input @input="function fn () { current++ }">',
'<input data-event-opts="{{[[\'input\',[[\'e0\',[\'$event\']]]]]}}" bindinput="__e"/>',
'with(this){if(!_isMounted){e0=function fn(){current++}}}'
)
......@@ -665,4 +672,4 @@ describe('mp:compiler', () => {
'<view class="_div"><block wx:if="{{ok}}"><block wx:for="{{1}}" wx:for-item="i" wx:for-index="__i0__" wx:key="*this"><foo vue-id="{{\'551070e6-1-\'+__i0__}}" bind:__l="__l"></foo></block></block></view>'
)
})
})
})
......@@ -14,6 +14,13 @@ function processElement (ast, state, isRoot) {
ast.type = 'view'
}
// 由于小程序端 default 不等同于默认插槽,统一移除 default 命名
if (ast.type === 'slot' && hasOwn(ast.attr, 'name') && ast.attr.name === 'default') {
delete ast.attr.name
} else if (hasOwn(ast.attr, 'slot') && ast.attr.slot === 'default') {
delete ast.attr.slot
}
if (hasOwn(ast.attr, 'textContent')) {
ast.children = [ast.attr.textContent]
delete ast.attr.textContent
......@@ -145,4 +152,4 @@ module.exports = function generate (ast, state) {
}
return code
}
}
......@@ -164,7 +164,7 @@ function traverseCreateElement (callExprNode, state) {
node.children = node.children.concat(normalizeChildren(traverseExpr(childNodes, state)))
} else {
node.children = normalizeChildren(traverseExpr(childNodes, state))
}
}
}
return node
}
......@@ -264,7 +264,7 @@ function genSlotNode (slotName, slotNode, fallbackNodes, state) {
attr: {
[prefix + 'if']: '{{$slots.' + slotName + '}}'
},
children: [slotNode]
children: [].concat(slotNode)
}, {
type: 'block',
attr: {
......@@ -461,4 +461,4 @@ function traverseCreateTextVNode (callExprNode, state) {
function traverseCreateEmptyVNode (callExprNode, state) {
return ''
}
}
......@@ -205,7 +205,14 @@ if (process.env.UNI_USING_NATIVE || process.env.UNI_USING_V3_NATIVE) {
const array = [{
from: path.resolve(process.env.UNI_INPUT_DIR, 'static'),
to: 'static'
}]
}]
const hybridHtmlPath = path.resolve(process.env.UNI_INPUT_DIR, 'hybrid/html')
if (fs.existsSync(hybridHtmlPath)) {
array.push({
from: hybridHtmlPath,
to: 'hybrid/html'
})
}
if (process.env.UNI_USING_NVUE_COMPILER) {
array.push({
from: path.resolve(getTemplatePath(), 'common'),
......
......@@ -696,13 +696,7 @@ var uid = 0;
* directives subscribing to it.
*/
var Dep = function Dep () {
// fixed by xxxxxx (nvue vuex)
/* eslint-disable no-undef */
if(typeof SharedObject !== 'undefined'){
this.id = SharedObject.uid++;
} else {
this.id = uid++;
}
this.id = uid++;
this.subs = [];
};
......@@ -739,7 +733,7 @@ Dep.prototype.notify = function notify () {
// can be evaluated at a time.
// fixed by xxxxxx (nvue shared vuex)
/* eslint-disable no-undef */
Dep.SharedObject = typeof SharedObject !== 'undefined' ? SharedObject : {};
Dep.SharedObject = {};
Dep.SharedObject.target = null;
Dep.SharedObject.targetStack = [];
......
......@@ -2,7 +2,8 @@ const fs = require('fs')
const path = require('path')
const {
removeExt,
normalizePath
normalizePath,
getPlatformExts
} = require('@dcloudio/uni-cli-shared')
const {
getComponentSet
......@@ -64,7 +65,7 @@ module.exports = function generateComponent (compilation) {
const concatenatedModules = modules.filter(module => module.modules)
const uniModuleId = modules.find(module => module.resource && normalizePath(module.resource) === uniPath).id
const wxssImports = {}
const styleImports = {}
Object.keys(assets).forEach(name => {
if (components.has(name.replace('.js', ''))) {
......@@ -126,20 +127,21 @@ module.exports = function generateComponent (compilation) {
assets[name].source = newSource
}
}
if (name.endsWith('.wxss')) {
const styleExtname = getPlatformExts().style
if (name.endsWith(styleExtname)) {
// 移除部分含有错误引用的 wxss 文件
let origSource = assets[name].source()
origSource = origSource.trim ? origSource.trim() : ''
const result = origSource.match(/^@import ["'](.+?)["']$/)
if (result) {
const wxssPath = path.join(path.dirname(name), result[1])
if (Object.keys(assets).includes(wxssPath)) {
wxssImports[wxssPath] = wxssImports[wxssPath] || []
wxssImports[wxssPath].push(name)
const stylePath = path.join(path.dirname(name), result[1])
if (Object.keys(assets).includes(stylePath)) {
styleImports[stylePath] = styleImports[stylePath] || []
styleImports[stylePath].push(name)
} else {
if (wxssImports[name]) {
wxssImports[name].forEach(name => delete assets[name])
delete wxssImports[name]
if (styleImports[name]) {
styleImports[name].forEach(name => delete assets[name])
delete styleImports[name]
}
delete assets[name]
}
......
......@@ -97,7 +97,7 @@ function queue (hooks, data) {
for (let i = 0; i < hooks.length; i++) {
const hook = hooks[i]
if (promise) {
promise = Promise.then(wrapperHook(hook))
promise = Promise.resolve(wrapperHook(hook))
} else {
const res = hook(data)
if (isPromise(res)) {
......
......@@ -45,7 +45,7 @@ let uni = {}
if (typeof Proxy !== 'undefined' && __PLATFORM__ !== 'app-plus') {
uni = new Proxy({}, {
get (target, name) {
if (target[name]) {
if (hasOwn(target, name)) {
return target[name]
}
if (baseApi[name]) {
......@@ -71,7 +71,7 @@ if (typeof Proxy !== 'undefined' && __PLATFORM__ !== 'app-plus') {
return promisify(name, wrapper(name, __GLOBAL__[name]))
},
set (target, name, value) {
target[name] = value
target[name] = value
return true
}
})
......
......@@ -63,10 +63,17 @@ export default {
const currentTarget = $event.currentTarget
const instance = currentTarget &&
currentTarget.__vue__ &&
currentTarget.__vue__.$getComponentDescriptor(currentTarget.__vue__, false)
$event = processEvent.call(this, $event.type, $event, {}, findUniTarget($event, this.$el) || $event.target,
$event.currentTarget)
$event.instance = instance
currentTarget.__vue__.$getComponentDescriptor(currentTarget.__vue__, false)
const $origEvent = $event
$event = processEvent.call(this, $origEvent.type, $origEvent, {}, findUniTarget($origEvent, this.$el) || $origEvent.target,
$origEvent.currentTarget)
$event.instance = instance
$event.preventDefault = function () {
return $origEvent.preventDefault()
}
$event.stopPropagation = function () {
return $origEvent.stopPropagation()
}
}
return $event
}
......
import api from './web-view-api'
const isAppPlus = /uni-app/i.test(navigator.userAgent)
const isAppPlus = /uni-app/i.test(navigator.userAgent)
const isHtml5Plus = /Html5Plus/i.test(navigator.userAgent)
const readyRE = /complete|loaded|interactive/
export function initWebviewApi (readyCallback) {
if (!isAppPlus) {
if (!isAppPlus && !isHtml5Plus) {
return
}
if (window.__dcloud_weex_postMessage || window.__dcloud_weex_) { // nvue web-view
......
const eventNames = [
'load',
'close',
......@@ -7,6 +6,9 @@ const eventNames = [
]
const ERROR_CODE_LIST = [-5001, -5002, -5003, -5004, -5005, -5006]
const EXPIRED_TIME = 1000 * 60 * 30
const EXPIRED_TEXT = { code: -5008, errMsg: '广告数据已过期,请重新加载' }
const ProviderType = { CSJ: 'csj', GDT: 'gdt' }
class RewardedVideoAd {
constructor (options = {}) {
......@@ -23,10 +25,14 @@ class RewardedVideoAd {
this._adError = ''
this._loadPromiseResolve = null
this._loadPromiseReject = null
this._lastLoadTime = 0
const rewardAd = this._rewardAd = plus.ad.createRewardedVideoAd(options)
rewardAd.onLoad((e) => {
this._isLoad = true
this._dispatchEvent('load', {})
this._lastLoadTime = Date.now()
if (this._loadPromiseResolve != null) {
this._loadPromiseResolve()
this._loadPromiseResolve = null
......@@ -43,7 +49,11 @@ class RewardedVideoAd {
const { code, message } = e
const data = { code: code, errMsg: message }
this._adError = message
if (code === -5008) {
this._isLoad = false
}
this._dispatchEvent('error', data)
// TODO
if ((code === -5005 || ERROR_CODE_LIST.index(code) === -1) && this._loadPromiseReject != null) {
this._loadPromiseReject(data)
this._loadPromiseReject = null
......@@ -52,6 +62,10 @@ class RewardedVideoAd {
this._loadAd()
}
get isExpired () {
return (Math.abs(Date.now() - this._lastLoadTime) > EXPIRED_TIME)
}
load () {
return new Promise((resolve, reject) => {
if (this._isLoad) {
......@@ -66,6 +80,15 @@ class RewardedVideoAd {
show () {
return new Promise((resolve, reject) => {
const provider = this.getProvider()
if (provider === ProviderType.CSJ && this.isExpired) {
this._isLoad = false
// TODO
this._dispatchEvent('error', EXPIRED_TEXT)
reject(new Error(EXPIRED_TEXT.errMsg))
return
}
if (this._isLoad) {
this._rewardAd.show()
resolve()
......
......@@ -15,7 +15,7 @@ const publishBackgroundAudioStateChange = (state, res = {}) => publish('onBackgr
state
}, res))
const events = ['play', 'pause', 'ended', 'stop']
const events = ['play', 'pause', 'ended', 'stop', 'canplay']
function initMusic () {
if (audio) {
......
......@@ -17,10 +17,11 @@ export function getSystemInfoSync () {
var screen = window.screen
var pixelRatio = window.devicePixelRatio
// 横屏时 iOS 获取的屏幕宽高颠倒,进行纠正
var landscape = Math.abs(window.orientation) === 90
var screenWidth = typeof window.orientation === 'number' ? Math[landscape ? 'max' : 'min'](screen.width, screen.height) : screen.width
var screenHeight = typeof window.orientation === 'number' ? Math[landscape ? 'min' : 'max'](screen.height, screen.width) : screen.height
var windowWidth = Math.min(window.innerWidth, document.documentElement.clientWidth, screenWidth)
const screenFix = /^Apple/.test(navigator.vendor) && typeof window.orientation === 'number'
const landscape = screenFix && Math.abs(window.orientation) === 90
var screenWidth = screenFix ? Math[landscape ? 'max' : 'min'](screen.width, screen.height) : screen.width
var screenHeight = screenFix ? Math[landscape ? 'min' : 'max'](screen.height, screen.width) : screen.height
var windowWidth = Math.min(window.innerWidth, document.documentElement.clientWidth, screenWidth) || screenWidth
var windowHeight = window.innerHeight
var language = navigator.language
var statusBarHeight = safeAreaInsets.top
......
......@@ -6,6 +6,7 @@
<div
ref="container"
class="uni-ad-container"
@click="onhandle"
/>
</uni-ad>
</template>
......@@ -31,27 +32,47 @@ class AdConfig {
this._callbacks = []
}
get (adpid, callback) {
get adConfig () {
return this._adConfig
}
_init () {
var config = this._getConfig()
if (config === null || !config.last) {
return
}
var td = Math.abs(Date.now() - config.last)
if (td < this.CACHE_TIME) {
this._adConfig = config.data
}
}
get (adpid, success, fail) {
if (this._adConfig != null) {
callback(this._adConfig.adpids[adpid])
this._doCallback(adpid, success, fail)
return
}
this._callbacks.push({ adpid: adpid, callback: callback })
this._loadAdConfig()
this._callbacks.push({
adpid: adpid,
success: success,
fail: fail
})
this._loadAdConfig(adpid)
}
_init () {
var config = this._getConfig()
if (config != null && config.last) {
var td = Math.abs(Date.now() - config.last)
if (td < this.CACHE_TIME) {
this._adConfig = config.data
}
_doCallback (adpid, success, fail) {
var data = this._adConfig
if (data.adpids[adpid]) {
success(data.adpids[adpid])
} else {
fail(this.ERROR_INVALID_ADPID)
}
}
_loadAdConfig (adpid, callback) {
_loadAdConfig (adpid) {
if (this._isLoading === true) {
return
}
......@@ -60,22 +81,35 @@ class AdConfig {
uni.request({
url: this.URL,
timeout: 3000,
method: 'GET',
timeout: 3000,
data: {
appid: '__UNI__ADD1C32'
adpid: adpid
},
dataType: 'json',
success: (res) => {
const rd = res.data
if (rd.ret === 0) {
const data = rd.data
this._adConfig = data
this._setConfig(data)
this._callbacks.forEach(({ adpid, success, fail }) => {
this._doCallback(adpid, success, fail)
})
} else {
this._callbacks.forEach((i) => {
i.callback(data.adpids[i.adpid])
i.fail(rd.message)
})
}
this._callbacks = []
},
fail: (err) => {
this._callbacks.forEach((i) => {
i.fail(err.errMsg)
})
this._callbacks = []
},
complete: (c) => {
this._isLoading = false
......@@ -103,8 +137,11 @@ class AdConfig {
}
Object.assign(AdConfig.prototype, {
URL: '//stream.dcloud.net.cn/dcloud/H5Config',
KEY: 'UNI_APP_AD',
CACHE_TIME: 1000 * 60 * 10
KEY: 'uni_app_ad_config',
CACHE_TIME: 1000 * 60 * 10,
ERROR_INVALID_ADPID: {
'-5002': '无效adpid'
}
})
const adProvider = {
......@@ -124,14 +161,7 @@ export default {
default: ''
}
},
data () {
return {
hidden: false
}
},
watch: {
hidden (val) {
},
adpid (val) {
if (val) {
this._loadData(val)
......@@ -142,25 +172,31 @@ export default {
this._pl = []
this._pd = {}
this._pi = 0
this._loadData()
this._checkTimer = null
this._checkTimerCount = 0
this._loadData()
},
beforeDestroy () {
this.$refs.container.innerHTML = ''
},
methods: {
onhandle (e) {
console.log('onhandle')
},
_loadData (adpid) {
AdConfig.instance.get(adpid || this.adpid, (data) => {
this._pd = data
this._pl = data.psp.split(',')
this._renderAd()
}, (err) => {
this.$trigger('error', {}, { message: err })
})
},
_renderAd () {
if (this._pi > this._pl.length - 1) {
return
}
var ap = this._pl[this._pi]
var data = this._pd[ap]
switch (ap) {
......@@ -176,14 +212,10 @@ export default {
var ad = document.createElement('script')
ad.src = data.src || data.url
var adView = document.createElement('div')
adView.setAttribute('id', this._randomId())
adView.appendChild(ad)
this.$refs.container.innerHTML = ''
this.$refs.container.append(adView)
this.$refs.container.append(ad)
// this._startCheckTimer()
this._startCheckTimer()
},
_renderKY (data) {
var ad = document.createElement('script')
......@@ -192,7 +224,7 @@ export default {
this.$refs.container.innerHTML = ''
this.$refs.container.append(ad)
// this._startCheckTimer()
this._startCheckTimer()
},
_renderNext () {
if (this._pi >= this._pl.length - 1) {
......@@ -203,7 +235,7 @@ export default {
this._renderAd()
},
_checkRender () {
var hasContent = this.$refs.container.querySelector('a') || this.$refs.container.querySelector('iframe')
var hasContent = (this.$refs.container.clientHeight > 40)
return hasContent
},
_startCheckTimer () {
......@@ -213,7 +245,9 @@ export default {
this._clearCheckTimer()
return
}
this._checkTimerCount++
if (this._checkTimerCount >= CHECK_RENDER_RETRY) {
this._clearCheckTimer()
this._renderNext()
......@@ -224,10 +258,8 @@ export default {
this._checkTimerCount = 0
if (this._checkTimer != null) {
window.clearInterval(this._checkTimer)
this._checkTimer = null
}
},
_randomId () {
return 'ad' + Date.now() + '' + parseInt(Math.random() * 1000)
}
}
}
......@@ -242,8 +274,4 @@ export default {
uni-ad[hidden] {
display: none;
}
uni-ad .uni-ad-container {
min-height: 1px;
}
</style>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册