提交 1a09f753 编写于 作者: Q qiang

fix(mp-alipay): 修复支付宝小程序启用基础库2.0后访问 $slots 报错的问题 #3529

上级 d3ec7e52
...@@ -31,11 +31,11 @@ describe('mp:compiler-mp-alipay', () => { ...@@ -31,11 +31,11 @@ describe('mp:compiler-mp-alipay', () => {
it('generate ref', () => { it('generate ref', () => {
assertCodegen( assertCodegen(
'<component1 ref="c1">text</component1>', '<component1 ref="c1">text</component1>',
'<component1 vue-id="551070e6-1" ref="__r" data-ref="c1" onVueInit="__l">text</component1>' '<component1 vue-id="551070e6-1" ref="__r" data-ref="c1" onVueInit="__l" vue-slots="{{[\'default\']}}">text</component1>'
) )
assertCodegen( assertCodegen(
'<component1 :ref="c2">text<text>123213</text></component1>', '<component1 :ref="c2">text<text>123213</text></component1>',
'<component1 vue-id="551070e6-1" ref="__r" data-ref="{{c2}}" onVueInit="__l">text<text>123213</text></component1>' '<component1 vue-id="551070e6-1" ref="__r" data-ref="{{c2}}" onVueInit="__l" vue-slots="{{[\'default\']}}">text<text>123213</text></component1>'
) )
assertCodegen( assertCodegen(
'<component1 v-for="item in items" ref="c3"></component1>', '<component1 v-for="item in items" ref="c3"></component1>',
...@@ -47,7 +47,7 @@ describe('mp:compiler-mp-alipay', () => { ...@@ -47,7 +47,7 @@ describe('mp:compiler-mp-alipay', () => {
) )
assertCodegen( assertCodegen(
'<component1>text</component1>', '<component1>text</component1>',
'<component1 vue-id="551070e6-1" data-com-type="wx" ref="__r" onVueInit="__l">text</component1>', '<component1 vue-id="551070e6-1" data-com-type="wx" ref="__r" onVueInit="__l" vue-slots="{{[\'default\']}}">text</component1>',
undefined, undefined,
undefined, undefined,
{ {
...@@ -56,7 +56,7 @@ describe('mp:compiler-mp-alipay', () => { ...@@ -56,7 +56,7 @@ describe('mp:compiler-mp-alipay', () => {
) )
assertCodegen( assertCodegen(
'<component1 @change="onChange" @cancle="onCancle">text</component1>', '<component1 @change="onChange" @cancle="onCancle">text</component1>',
'<component1 onChange="__e" onCancle="__e" vue-id="551070e6-1" data-event-opts="{{[[\'^change\',[[\'onChange\']]],[\'^cancle\',[[\'onCancle\']]]]}}" data-com-type="wx" ref="__r" data-event-list="onChange,onCancle" onVueInit="__l">text</component1>', '<component1 onChange="__e" onCancle="__e" vue-id="551070e6-1" data-event-opts="{{[[\'^change\',[[\'onChange\']]],[\'^cancle\',[[\'onCancle\']]]]}}" data-com-type="wx" ref="__r" data-event-list="onChange,onCancle" onVueInit="__l" vue-slots="{{[\'default\']}}">text</component1>',
undefined, undefined,
undefined, undefined,
{ {
...@@ -65,7 +65,7 @@ describe('mp:compiler-mp-alipay', () => { ...@@ -65,7 +65,7 @@ describe('mp:compiler-mp-alipay', () => {
) )
assertCodegen( assertCodegen(
'<credit-pay @change="onChange" @cancle="onCancle">text</credit-pay>', '<credit-pay @change="onChange" @cancle="onCancle">text</credit-pay>',
'<plugin-wrapper onChange="__e" onCancle="__e" vue-id="551070e6-1" onPluginWrap="__w" data-event-opts="{{[[\'^change\',[[\'onChange\']]],[\'^cancle\',[[\'onCancle\']]]]}}" data-com-type="wx" data-event-list="onChange,onCancle" onVueInit="__l"><credit-pay onChange="{{\'onChange\'+\'551070e6-1\'}}" onCancle="{{\'onCancle\'+\'551070e6-1\'}}" onVueInit="__l">text</credit-pay></plugin-wrapper>', '<plugin-wrapper onChange="__e" onCancle="__e" vue-id="551070e6-1" onPluginWrap="__w" data-event-opts="{{[[\'^change\',[[\'onChange\']]],[\'^cancle\',[[\'onCancle\']]]]}}" data-com-type="wx" data-event-list="onChange,onCancle" onVueInit="__l" vue-slots="{{[\'default\']}}"><credit-pay onChange="{{\'onChange\'+\'551070e6-1\'}}" onCancle="{{\'onCancle\'+\'551070e6-1\'}}" onVueInit="__l" vue-slots="{{[\'default\']}}">text</credit-pay></plugin-wrapper>',
undefined, undefined,
undefined, undefined,
{ {
...@@ -82,33 +82,33 @@ describe('mp:compiler-mp-alipay', () => { ...@@ -82,33 +82,33 @@ describe('mp:compiler-mp-alipay', () => {
it('generate default slot', () => { it('generate default slot', () => {
assertCodegen( assertCodegen(
'<component1>text</component1>', '<component1>text</component1>',
'<component1 vue-id="551070e6-1" onVueInit="__l">text</component1>' '<component1 vue-id="551070e6-1" onVueInit="__l" vue-slots="{{[\'default\']}}">text</component1>'
) )
assertCodegen( assertCodegen(
'<component1>text<text>123213</text></component1>', '<component1>text<text>123213</text></component1>',
'<component1 vue-id="551070e6-1" onVueInit="__l">text<text>123213</text></component1>' '<component1 vue-id="551070e6-1" onVueInit="__l" vue-slots="{{[\'default\']}}">text<text>123213</text></component1>'
) )
assertCodegen( assertCodegen(
'<component1>text<block slot="right"></block></component1>', '<component1>text<block slot="right"></block></component1>',
'<component1 vue-id="551070e6-1" onVueInit="__l">text<view slot="right"></view></component1>' '<component1 vue-id="551070e6-1" onVueInit="__l" vue-slots="{{[\'default\',\'right\']}}">text<view slot="right"></view></component1>'
) )
}) })
it('generate scoped slot', () => { it('generate scoped slot', () => {
assertCodegen( assertCodegen(
'<component1 :text="\'text\'"><template v-slot="props"><view :class="{text:props.text}">{{props.text}}</view></template></component1>', '<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>' '<component1 vue-id="551070e6-1" text="text" onVueInit="__l" vue-slots="{{[\'default\']}}"><view slot-scope="props"><view class="{{((props.text)?\'text\':\'\')}}">{{props.text}}</view></view></component1>'
) )
assertCodegen( assertCodegen(
'<component1 :text="\'text\'"><template v-slot="{text}"><view :class="{text:text}">{{text}}</view></template></component1>', '<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>' '<component1 vue-id="551070e6-1" text="text" onVueInit="__l" vue-slots="{{[\'default\']}}"><view slot-scope="__SCOPED__"><view class="{{((__SCOPED__.text)?\'text\':\'\')}}">{{__SCOPED__.text}}</view></view></component1>'
) )
}) })
it('generate scoped slot with scopedSlotsCompiler: auto', () => { it('generate scoped slot with scopedSlotsCompiler: auto', () => {
assertCodegen( assertCodegen(
'<my-component><template v-slot="{item}">{{item}}<template></my-component>', '<my-component><template v-slot="{item}">{{item}}<template></my-component>',
'<my-component vue-id="551070e6-1" onVueInit="__l"><view slot-scope="__SCOPED__">{{__SCOPED__.item}}</view></my-component>', '<my-component vue-id="551070e6-1" onVueInit="__l" vue-slots="{{[\'default\']}}"><view slot-scope="__SCOPED__">{{__SCOPED__.item}}</view></my-component>',
'with(this){}', 'with(this){}',
{ {
scopedSlotsCompiler: 'auto' scopedSlotsCompiler: 'auto'
...@@ -116,7 +116,7 @@ describe('mp:compiler-mp-alipay', () => { ...@@ -116,7 +116,7 @@ describe('mp:compiler-mp-alipay', () => {
) )
assertCodegen( assertCodegen(
'<my-component><template v-slot="{item}">{{getValue(item)}}<template></my-component>', '<my-component><template v-slot="{item}">{{getValue(item)}}<template></my-component>',
'<my-component scoped-slots-compiler="augmented" vue-id="551070e6-1" onVueInit="__l"><block a:if="{{$root.m0}}">{{$root.m1}}</block></my-component>', '<my-component scoped-slots-compiler="augmented" vue-id="551070e6-1" onVueInit="__l" vue-slots="{{[\'default\']}}"><block a:if="{{$root.m0}}">{{$root.m1}}</block></my-component>',
'with(this){var m0=$hasScopedSlotsParams("551070e6-1");var m1=m0?getValue($getScopedSlotsParams("551070e6-1","default","item")):null;$mp.data=Object.assign({},{$root:{m0:m0,m1:m1}})}', 'with(this){var m0=$hasScopedSlotsParams("551070e6-1");var m1=m0?getValue($getScopedSlotsParams("551070e6-1","default","item")):null;$mp.data=Object.assign({},{$root:{m0:m0,m1:m1}})}',
{ {
scopedSlotsCompiler: 'auto' scopedSlotsCompiler: 'auto'
...@@ -124,7 +124,7 @@ describe('mp:compiler-mp-alipay', () => { ...@@ -124,7 +124,7 @@ describe('mp:compiler-mp-alipay', () => {
) )
assertCodegen( assertCodegen(
'<my-component><template v-slot="item">{{getValue(item.text)}}<template></my-component>', '<my-component><template v-slot="item">{{getValue(item.text)}}<template></my-component>',
'<my-component scoped-slots-compiler="augmented" vue-id="551070e6-1" onVueInit="__l"><block a:if="{{$root.m0}}">{{$root.m1}}</block></my-component>', '<my-component scoped-slots-compiler="augmented" vue-id="551070e6-1" onVueInit="__l" vue-slots="{{[\'default\']}}"><block a:if="{{$root.m0}}">{{$root.m1}}</block></my-component>',
'with(this){var m0=$hasScopedSlotsParams("551070e6-1");var m1=m0?getValue($getScopedSlotsParams("551070e6-1","default").text):null;$mp.data=Object.assign({},{$root:{m0:m0,m1:m1}})}', 'with(this){var m0=$hasScopedSlotsParams("551070e6-1");var m1=m0?getValue($getScopedSlotsParams("551070e6-1","default").text):null;$mp.data=Object.assign({},{$root:{m0:m0,m1:m1}})}',
{ {
scopedSlotsCompiler: 'auto' scopedSlotsCompiler: 'auto'
...@@ -207,7 +207,7 @@ describe('mp:compiler-mp-alipay', () => { ...@@ -207,7 +207,7 @@ describe('mp:compiler-mp-alipay', () => {
it('generate attrs with mergeVirtualHostAttributes', () => { it('generate attrs with mergeVirtualHostAttributes', () => {
assertCodegen( assertCodegen(
'<custom-view>hello world</custom-view>', '<custom-view>hello world</custom-view>',
'<custom-view vue-id="551070e6-1" onVueInit="__l" virtualHostStyle="{{virtualHostStyle}}" virtualHostClass="{{(virtualHostClass)}}">hello world</custom-view>', '<custom-view vue-id="551070e6-1" onVueInit="__l" virtualHostStyle="{{virtualHostStyle}}" virtualHostClass="{{(virtualHostClass)}}" vue-slots="{{[\'default\']}}">hello world</custom-view>',
'with(this){}', 'with(this){}',
{ {
mergeVirtualHostAttributes: true mergeVirtualHostAttributes: true
...@@ -215,7 +215,7 @@ describe('mp:compiler-mp-alipay', () => { ...@@ -215,7 +215,7 @@ describe('mp:compiler-mp-alipay', () => {
) )
assertCodegen( assertCodegen(
'<custom-view :class="class1" :style="style">hello world</custom-view>', '<custom-view :class="class1" :style="style">hello world</custom-view>',
'<custom-view vue-id="551070e6-1" onVueInit="__l" virtualHostStyle="{{(style)+virtualHostStyle}}" virtualHostClass="{{((class1)+\' \'+virtualHostClass)}}">hello world</custom-view>', '<custom-view vue-id="551070e6-1" onVueInit="__l" virtualHostStyle="{{(style)+virtualHostStyle}}" virtualHostClass="{{((class1)+\' \'+virtualHostClass)}}" vue-slots="{{[\'default\']}}">hello world</custom-view>',
'with(this){}', 'with(this){}',
{ {
mergeVirtualHostAttributes: true mergeVirtualHostAttributes: true
...@@ -223,7 +223,7 @@ describe('mp:compiler-mp-alipay', () => { ...@@ -223,7 +223,7 @@ describe('mp:compiler-mp-alipay', () => {
) )
assertCodegen( assertCodegen(
'<view><custom-view>hello world</custom-view></view>', '<view><custom-view>hello world</custom-view></view>',
'<view class="{{(virtualHostClass)}}" style="{{virtualHostStyle}}"><custom-view vue-id="551070e6-1" onVueInit="__l">hello world</custom-view></view>', '<view class="{{(virtualHostClass)}}" style="{{virtualHostStyle}}"><custom-view vue-id="551070e6-1" onVueInit="__l" vue-slots="{{[\'default\']}}">hello world</custom-view></view>',
'with(this){}', 'with(this){}',
{ {
mergeVirtualHostAttributes: true mergeVirtualHostAttributes: true
...@@ -231,7 +231,7 @@ describe('mp:compiler-mp-alipay', () => { ...@@ -231,7 +231,7 @@ describe('mp:compiler-mp-alipay', () => {
) )
assertCodegen( assertCodegen(
'<view><custom-view :class="class1" :style="style">hello world</custom-view></view>', '<view><custom-view :class="class1" :style="style">hello world</custom-view></view>',
'<view class="{{(virtualHostClass)}}" style="{{virtualHostStyle}}"><custom-view vue-id="551070e6-1" onVueInit="__l" virtualHostStyle="{{(style)}}" virtualHostClass="{{(class1)}}">hello world</custom-view></view>', '<view class="{{(virtualHostClass)}}" style="{{virtualHostStyle}}"><custom-view vue-id="551070e6-1" onVueInit="__l" virtualHostStyle="{{(style)}}" virtualHostClass="{{(class1)}}" vue-slots="{{[\'default\']}}">hello world</custom-view></view>',
'with(this){}', 'with(this){}',
{ {
mergeVirtualHostAttributes: true mergeVirtualHostAttributes: true
......
...@@ -46,61 +46,64 @@ function processElement (ast, state, isRoot) { ...@@ -46,61 +46,64 @@ function processElement (ast, state, isRoot) {
} else if (platformName !== 'mp-baidu') { } else if (platformName !== 'mp-baidu') {
ast.attr['bind:' + INTERNAL_EVENT_LINK] = INTERNAL_EVENT_LINK ast.attr['bind:' + INTERNAL_EVENT_LINK] = INTERNAL_EVENT_LINK
} }
// TODO 过滤小程序原生组件
if (mergeVirtualHostAttributes && platform.isComponent(ast.type)) { {
const obj = { // 处理自定义组件虚拟节点样式
style: VIRTUAL_HOST_STYLE, if (mergeVirtualHostAttributes) {
class: VIRTUAL_HOST_CLASS const obj = {
} style: VIRTUAL_HOST_STYLE,
Object.keys(obj).forEach(key => { class: VIRTUAL_HOST_CLASS
if (key in ast.attr) {
ast.attr[obj[key]] = ast.attr[key]
} }
// 支付宝小程序自定义组件外部属性始终无效 Object.keys(obj).forEach(key => {
if (platformName === 'mp-alipay') { if (key in ast.attr) {
delete ast.attr[key] ast.attr[obj[key]] = ast.attr[key]
}
// 支付宝小程序自定义组件外部属性始终无效
if (platformName === 'mp-alipay') {
delete ast.attr[key]
}
})
}
// 标记自定义组件插槽
const children = ast.children
// default slot
let defaultSlot = false
const slots = []
for (let i = children.length - 1; i >= 0; i--) {
const childElement = children[i]
/**
* 仅百度、字节支持使用 block 作为命名插槽根节点
* 此处为了统一仅忽略默认插槽
* <block slot="left"></block> => <view slot="left"></view>
*/
if (typeof childElement !== 'string' && childElement.attr.slot) {
const slot = childElement.attr.slot
if (slot && slot !== 'default' && childElement.type === 'block') {
childElement.type = 'view'
}
slots.push(slot)
} else {
defaultSlot = true
} }
}) }
} if (defaultSlot) {
slots.push('default')
const children = ast.children }
// default slot if (ast.attr.generic) {
let defaultSlot = false Object.keys(ast.attr.generic).forEach(scopedSlotName => {
const slots = [] slots.push(scopedSlotName)
for (let i = children.length - 1; i >= 0; i--) { })
const childElement = children[i] if (platformName === 'mp-toutiao' || platformName === 'mp-lark') {
/** // 用于字节跳动|飞书小程序模拟抽象节点
* 仅百度、字节支持使用 block 作为命名插槽根节点 ast.attr.generic = `{{${JSON.stringify(ast.attr.generic)}}}`.replace(/"/g, '\'')
* 此处为了统一仅忽略默认插槽 } else {
* <block slot="left"></block> => <view slot="left"></view> delete ast.attr.generic
*/
if (typeof childElement !== 'string' && childElement.attr.slot) {
const slot = childElement.attr.slot
if (slot && slot !== 'default' && childElement.type === 'block') {
childElement.type = 'view'
} }
slots.push(slot)
} else {
defaultSlot = true
} }
} if (slots.length) { // 标记 slots
if (defaultSlot) { ast.attr['vue-slots'] = '{{[' + slots.reverse().map(slotName => `'${slotName}'`).join(',') + ']}}'
slots.push('default')
}
if (ast.attr.generic) {
Object.keys(ast.attr.generic).forEach(scopedSlotName => {
slots.push(scopedSlotName)
})
if (platformName === 'mp-toutiao' || platformName === 'mp-lark') {
// 用于字节跳动|飞书小程序模拟抽象节点
ast.attr.generic = `{{${JSON.stringify(ast.attr.generic)}}}`.replace(/"/g, '\'')
} else {
delete ast.attr.generic
} }
} }
if (slots.length && platformName !== 'mp-alipay') { // 标记 slots
ast.attr['vue-slots'] = '{{[' + slots.reverse().map(slotName => `'${slotName}'`).join(',') + ']}}'
}
if (ast.attr.id && ast.attr.id.indexOf('{{') === 0) { if (ast.attr.id && ast.attr.id.indexOf('{{') === 0) {
state.tips.add(uniI18n.__('templateCompiler.idAttribNotAllowInCustomComponentProps', { 0: ast.type })) state.tips.add(uniI18n.__('templateCompiler.idAttribNotAllowInCustomComponentProps', { 0: ast.type }))
} }
......
...@@ -8,23 +8,6 @@ import { ...@@ -8,23 +8,6 @@ import {
} from './util' } from './util'
export default function parseApp (vm) { export default function parseApp (vm) {
Object.defineProperty(Vue.prototype, '$slots', {
get () {
return this.$scope && this.$scope.props.$slots
},
set () {
}
})
Object.defineProperty(Vue.prototype, '$scopedSlots', {
get () {
return this.$scope && this.$scope.props.$scopedSlots
},
set () {
}
})
Vue.prototype.$onAliGetAuthorize = function onAliGetAuthorize (method, $event) { Vue.prototype.$onAliGetAuthorize = function onAliGetAuthorize (method, $event) {
my.getPhoneNumber({ my.getPhoneNumber({
success: (res) => { success: (res) => {
......
...@@ -22,6 +22,29 @@ import { ...@@ -22,6 +22,29 @@ import {
initSpecialMethods initSpecialMethods
} from './util' } from './util'
function initSlots (vm, vueSlots) {
const $slots = Object.create(null)
// 未启用小程序基础库 2.0 时,组件实例支持支持访问 $slots、$scopedSlots
Object.defineProperty(vm, '$slots', {
get () {
const $scope = this.$scope
return ($scope && $scope.props.$slots) || ($scope && $scope.props.$scopedSlots ? {} : $slots)
}
})
Object.defineProperty(vm, '$scopedSlots', {
get () {
const $scope = this.$scope
return ($scope && $scope.props.$scopedSlots) || ($scope && $scope.props.$slots ? {} : $slots)
}
})
// 处理$slots,$scopedSlots(暂不支持动态变化$slots)
if (Array.isArray(vueSlots) && vueSlots.length) {
vueSlots.forEach(slotName => {
$slots[slotName] = true
})
}
}
function initVm (VueComponent) { function initVm (VueComponent) {
if (this.$vm) { if (this.$vm) {
return return
...@@ -46,6 +69,8 @@ function initVm (VueComponent) { ...@@ -46,6 +69,8 @@ function initVm (VueComponent) {
// 初始化 vue 实例 // 初始化 vue 实例
this.$vm = new VueComponent(options) this.$vm = new VueComponent(options)
initSlots(this.$vm, properties.vueSlots)
// 触发首次 setData // 触发首次 setData
this.$vm.$mount() this.$vm.$mount()
} else { } else {
...@@ -61,6 +86,9 @@ function initVm (VueComponent) { ...@@ -61,6 +86,9 @@ function initVm (VueComponent) {
// 初始化 vue 实例 // 初始化 vue 实例
this.$vm = new VueComponent(options) this.$vm = new VueComponent(options)
handleRef.call(options.parent.$scope, this) handleRef.call(options.parent.$scope, this)
initSlots(this.$vm, properties.vueSlots)
// 触发首次 setData // 触发首次 setData
this.$vm.$mount() this.$vm.$mount()
...@@ -83,9 +111,7 @@ export default function parseComponent (vueComponentOptions) { ...@@ -83,9 +111,7 @@ export default function parseComponent (vueComponentOptions) {
} }
Object.keys(properties).forEach(key => { Object.keys(properties).forEach(key => {
if (key !== 'vueSlots') { props[key] = properties[key].value
props[key] = properties[key].value
}
}) })
const componentOptions = { const componentOptions = {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册