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

feat(mp): betterScopedSlots -> scopedSlotsCompiler

上级 58c978ae
......@@ -87,6 +87,49 @@ describe('mp:compiler-mp-alipay', () => {
)
})
it('generate scoped slot with scopedSlotsCompiler: auto', () => {
assertCodegen(
'<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>',
'with(this){}',
{
scopedSlotsCompiler: 'auto'
}
)
assertCodegen(
'<my-component><template v-slot="{item}">{{getValue(item)}}<template></my-component>',
'<my-component scoped-slots-compiler="augmented" vue-id="551070e6-1" onVueInit="__l"><block><block a:if="{{$root.m0}}">{{$root.m1}}</block></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}})}',
{
scopedSlotsCompiler: 'auto'
}
)
assertCodegen(
'<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><block a:if="{{$root.m0}}">{{$root.m1}}</block></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}})}',
{
scopedSlotsCompiler: 'auto'
}
)
assertCodegen(
'<view><slot :item="item"><slot></view>',
'<view><block a:if="{{$slots.$default}}"><slot item="{{item}}"></slot></block><block a:else><slot></slot></block></view>',
'with(this){if($mp.component.props.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",{"item":item})}}',
{
scopedSlotsCompiler: 'auto'
}
)
assertCodegen(
'<view><slot v-bind="object"><slot></view>',
'<view><block a:if="{{$slots.$default}}"><slot></slot></block><block a:else><slot></slot></block></view>',
'with(this){if($mp.component.props.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",object)}}',
{
scopedSlotsCompiler: 'auto'
}
)
})
it('generate class binding', () => {
assertCodegen(
'<div :class="{ active: isActive }">1</div>',
......
......@@ -65,6 +65,49 @@ describe('mp:compiler-mp-baidu', () => {
)
})
it('generate scoped slot with scopedSlotsCompiler: auto', () => {
assertCodegen(
'<my-component><template v-slot="{item}">{{item}}<template></my-component>',
'<my-component vue-id="551070e6-1" vue-slots="{{[\'default\']}}"><view>{{item}}</view></my-component>',
'with(this){}',
{
scopedSlotsCompiler: 'auto'
}
)
assertCodegen(
'<my-component><template v-slot="{item}">{{getValue(item)}}<template></my-component>',
'<my-component scoped-slots-compiler="augmented" vue-id="551070e6-1" vue-slots="{{[\'default\']}}"><block><block s-if="{{$root.m0}}">{{$root.m1}}</block></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}})}',
{
scopedSlotsCompiler: 'auto'
}
)
assertCodegen(
'<my-component><template v-slot="item">{{getValue(item.text)}}<template></my-component>',
'<my-component scoped-slots-compiler="augmented" vue-id="551070e6-1" vue-slots="{{[\'default\']}}"><block><block s-if="{{$root.m0}}">{{$root.m1}}</block></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}})}',
{
scopedSlotsCompiler: 'auto'
}
)
assertCodegen(
'<view><slot :item="item"><slot></view>',
'<view><block s-if="{{$slots.default}}"><slot var-item="item"></slot></block><block s-else><slot></slot></block></view>',
'with(this){if($mp.component.data.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",{"item":item})}}',
{
scopedSlotsCompiler: 'auto'
}
)
assertCodegen(
'<view><slot v-bind="object"><slot></view>',
'<view><block s-if="{{$slots.default}}"><slot></slot></block><block s-else><slot></slot></block></view>',
'with(this){if($mp.component.data.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",object)}}',
{
scopedSlotsCompiler: 'auto'
}
)
})
it('generate vue id', () => {
assertCodegen(
'<Test/>',
......
......@@ -82,13 +82,64 @@ describe('mp:compiler-mp-weixin', () => {
)
})
it('generate scoped slot with filter', () => {
it('generate scoped slot with scopedSlotsCompiler: auto', () => {
assertCodegen(
'<my-component><template v-slot="{item}">{{item}}<template></my-component>',
'<my-component generic:scoped-slots-default="test-my-component-default" data-vue-generic="scoped" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'default\']}}"></my-component>',
'with(this){}',
{
scopedSlotsCompiler: 'auto'
}
)
assertCodegen(
'<my-component><template v-slot="{item}">{{getValue(item)}}<template></my-component>',
'<my-component scoped-slots-compiler="augmented" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'default\']}}"><block><block wx:if="{{$root.m0}}">{{$root.m1}}</block></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}})}',
{
scopedSlotsCompiler: 'auto'
}
)
assertCodegen(
'<my-component><template v-slot="item">{{getValue(item.text)}}<template></my-component>',
'<my-component scoped-slots-compiler="augmented" vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'default\']}}"><block><block wx:if="{{$root.m0}}">{{$root.m1}}</block></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}})}',
{
scopedSlotsCompiler: 'auto'
}
)
assertCodegen(
'<view><slot :item="item"><slot></view>',
'<view><block wx:if="{{$slots.default}}"><slot></slot><scoped-slots-default item="{{item}}" class="scoped-ref" bind:__l="__l"></scoped-slots-default></block><block wx:else><slot></slot></block></view>',
'with(this){if($mp.component.data.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",{"item":item})}}',
{
scopedSlotsCompiler: 'auto'
}
)
assertCodegen(
'<view><slot :item="getValue(item)"><slot></view>',
'<view><block wx:if="{{$slots.default}}"><slot></slot><scoped-slots-default item="{{$root.m0}}" class="scoped-ref" bind:__l="__l"></scoped-slots-default></block><block wx:else><slot></slot></block></view>',
'with(this){var m0=getValue(item);$mp.data=Object.assign({},{$root:{m0:m0}});if($mp.component.data.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",{"item":$root.m0})}}',
{
scopedSlotsCompiler: 'auto'
}
)
assertCodegen(
'<view><slot v-bind="object"><slot></view>',
'<view><block wx:if="{{$slots.default}}"><slot></slot></block><block wx:else><slot></slot></block></view>',
'with(this){if($mp.component.data.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",object)}}',
{
scopedSlotsCompiler: 'auto'
}
)
})
it('generate scoped slot with scopedSlotsCompiler: augmented', () => {
assertCodegen(
'<my-component><template v-slot="{item}">{{getValue(item)}}<template></my-component>',
'<my-component vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'default\']}}"><block><block wx:if="{{$root.m0}}">{{$root.m1}}</block></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}})}',
{
betterScopedSlots: true
scopedSlotsCompiler: 'augmented'
}
)
assertCodegen(
......@@ -96,7 +147,7 @@ describe('mp:compiler-mp-weixin', () => {
'<my-component vue-id="551070e6-1" bind:__l="__l" vue-slots="{{[\'default\']}}"><block><block wx:if="{{$root.m0}}">{{$root.m1}}</block></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}})}',
{
betterScopedSlots: true
scopedSlotsCompiler: 'augmented'
}
)
assertCodegen(
......@@ -104,7 +155,15 @@ describe('mp:compiler-mp-weixin', () => {
'<view><block wx:if="{{$slots.default}}"><slot></slot></block><block wx:else><slot></slot></block></view>',
'with(this){$setScopedSlotsParams("default",{"item":item})}',
{
betterScopedSlots: true
scopedSlotsCompiler: 'augmented'
}
)
assertCodegen(
'<view><slot :item="getValue(item)"><slot></view>',
'<view><block wx:if="{{$slots.default}}"><slot></slot></block><block wx:else><slot></slot></block></view>',
'with(this){$setScopedSlotsParams("default",{"item":getValue(item)})}',
{
scopedSlotsCompiler: 'augmented'
}
)
assertCodegen(
......@@ -112,7 +171,7 @@ describe('mp:compiler-mp-weixin', () => {
'<view><block wx:if="{{$slots.default}}"><slot></slot></block><block wx:else><slot></slot></block></view>',
'with(this){$setScopedSlotsParams("default",object)}',
{
betterScopedSlots: true
scopedSlotsCompiler: 'augmented'
}
)
})
......
......@@ -114,7 +114,22 @@ module.exports = function traverse (ast, state) {
}
if (renderSlotStatementArray.length) {
blockStatementBody.push(...renderSlotStatementArray)
if (state.options.scopedSlotsCompiler === 'auto') {
const node = t.ifStatement(
t.binaryExpression('===',
t.memberExpression(t.memberExpression(t.memberExpression(t.identifier('$mp'), t.identifier('component')), t.identifier(state.options.platform.name === 'mp-alipay' ? 'props' : 'data')), t.identifier('scopedSlotsCompiler')), t.stringLiteral('augmented')
),
t.blockStatement([
t.variableDeclaration('const', [t.variableDeclarator(t.identifier('$root'),
t.memberExpression(t.memberExpression(t.identifier('$mp'), t.identifier('data')), t.identifier('$root'))
)]),
...renderSlotStatementArray
])
)
blockStatementBody.push(node)
} else {
blockStatementBody.push(...renderSlotStatementArray)
}
}
reIdentifier(identifierArray)
......
......@@ -15,13 +15,15 @@ module.exports = function getRenderSlot (path, state) {
const newProperties = []
propertiesPath.forEach(path => {
const properties = path.get('key').isStringLiteral({ value: 'SLOT_DEFAULT' }) ? oldProperties : newProperties
properties.push(path.node)
properties.push(state.options.scopedSlotsCompiler === 'auto' ? path.node : t.cloneDeep(path.node))
})
if (!newProperties.length) {
return
}
valueNode = t.objectExpression(newProperties)
arg2.replaceWith(t.objectExpression(oldProperties))
if (state.options.scopedSlotsCompiler !== 'auto') {
arg2.replaceWith(t.objectExpression(oldProperties))
}
} else {
valueNode = arg2.node
}
......
const t = require('@babel/types')
const {
METHOD_BUILT_IN,
METHOD_CREATE_EMPTY_VNODE
} = require('../../constants')
function needSlotMode (path, ids) {
let need
path.traverse({
noScope: false,
Identifier (path) {
const name = path.node.name
if (path.key !== 'key' && (path.key !== 'property' || path.parent.computed)) {
// 使用方法或作用域外数据
if (name in ids) {
need = path.key === 'callee' ? true : need
} else if (!path.scope.hasBinding(name) && !METHOD_BUILT_IN.includes(name)) {
need = true
}
}
}
})
return need
}
function replaceId (path, ids) {
let replaced
path.traverse({
......@@ -44,11 +64,15 @@ module.exports = function getResolveScopedSlots (parent, state) {
updateIds(vueId, slot, params.node.name)
}
const fnBody = fn.get('value.body')
if (replaceId(fnBody, ids)) {
const orgin = fnBody.get('body.0.argument')
const elements = orgin.get('elements')
const node = (elements.length === 1 ? elements[0] : orgin).node
const test = t.callExpression(t.identifier('$hasScopedSlotsParams'), [vueId])
orgin.replaceWith(t.arrayExpression([t.conditionalExpression(test, node, t.callExpression(t.identifier(METHOD_CREATE_EMPTY_VNODE), []))]))
if (needSlotMode(fnBody, ids)) {
if (replaceId(fnBody, ids)) {
const orgin = fnBody.get('body.0.argument')
const elements = orgin.get('elements')
const node = (elements.length === 1 ? elements[0] : orgin).node
const test = t.callExpression(t.identifier('$hasScopedSlotsParams'), [vueId])
orgin.replaceWith(t.arrayExpression([t.conditionalExpression(test, node, t.callExpression(t.identifier(METHOD_CREATE_EMPTY_VNODE), []))]))
// scopedSlotsCompiler auto
parent.get('arguments.0.elements.0').node.scopedSlotsCompiler = 'augmented'
}
}
}
......@@ -221,7 +221,7 @@ module.exports = {
this
)
)
} else if (this.options.betterScopedSlots) {
} else if (this.options.scopedSlotsCompiler === 'auto' || this.options.scopedSlotsCompiler === 'augmented') {
if (methodName === METHOD_RESOLVE_SCOPED_SLOTS) {
getResolveScopedSlots(path, this)
} else if (methodName === METHOD_RENDER_SLOT) {
......
......@@ -304,7 +304,7 @@ function traverseRenderSlot (callExprNode, state) {
const slotName = callExprNode.arguments[0].value
let deleteSlotName = false // 标记是否组件 slot 手动指定了 name="default"
if (!state.options.betterScopedSlots && callExprNode.arguments.length > 2) { // 作用域插槽
if (state.options.scopedSlotsCompiler !== 'augmented' && callExprNode.arguments.length > 2) { // 作用域插槽
const props = {}
callExprNode.arguments[2].properties.forEach(property => {
props[property.key.value] = genCode(property.value)
......@@ -369,11 +369,11 @@ function traverseResolveScopedSlots (callExprNode, state) {
})
const slotName = keyProperty.value.value
const returnExprNodes = fnProperty.value.body.body[0].argument
if (!state.options.betterScopedSlots && !proxyProperty) {
const parentNode = callExprNode.$node
if (slotNode.scopedSlotsCompiler !== 'augmented' && !proxyProperty) {
const resourcePath = state.options.resourcePath
const ownerName = path.basename(resourcePath, path.extname(resourcePath))
const parentNode = callExprNode.$node
const parentName = parentNode.type
const paramExprNode = fnProperty.value.params[0]
......@@ -397,6 +397,9 @@ function traverseResolveScopedSlots (callExprNode, state) {
state
)
}
if (state.options.scopedSlotsCompiler === 'auto' && slotNode.scopedSlotsCompiler === 'augmented') {
parentNode.attr['scoped-slots-compiler'] = 'augmented'
}
const children = normalizeChildren(traverseExpr(returnExprNodes, state))
// 除百度、字节外其他小程序仅默认插槽可以支持多个节点
if (single(children, slotName, ['template', 'block'])) {
......
......@@ -261,9 +261,10 @@ if (platformOptions.usingComponents === true) {
}
}
if (platformOptions.betterScopedSlots) {
process.env.BETTER_SCOPED_SLOTS = true
}
// 兼容历史配置 betterScopedSlots
const modes = ['legacy', 'auto', 'augmented']
const scopedSlotsCompiler = platformOptions.scopedSlotsCompiler ? platformOptions.scopedSlotsCompiler : modes[2]
process.env.SCOPED_SLOTS_COMPILER = modes.includes(scopedSlotsCompiler) ? scopedSlotsCompiler : modes[1]
if (
process.env.UNI_USING_COMPONENTS ||
......
......@@ -66,7 +66,7 @@ module.exports = function (content, map) {
Object.assign(vueLoaderOptions.options.compilerOptions, {
mp: {
platform: process.env.UNI_PLATFORM,
betterScopedSlots: process.env.BETTER_SCOPED_SLOTS
scopedSlotsCompiler: process.env.SCOPED_SLOTS_COMPILER
},
filterModules,
filterTagName,
......
......@@ -237,6 +237,11 @@ export function initProperties (props, isBehavior = false, file = '') {
type: Object,
value: null
}
// scopedSlotsMode auto
properties.scopedSlotsMode = {
type: String,
value: ''
}
properties.vueSlots = { // 小程序不能直接定义 $slots 的 props,所以通过 vueSlots 转换到 $slots
type: null,
value: [],
......@@ -572,4 +577,4 @@ export function handleEvent (event) {
) {
return ret[0]
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册