提交 c23516a6 编写于 作者: Q qiang

fix(mp): 修复 v-for 嵌套 slot 编译报错的问题 question/125108

上级 7e774b0b
......@@ -115,7 +115,7 @@ describe('mp:compiler-mp-alipay', () => {
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($scope.props.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",{"item":item})}}',
'with(this){if($scope.props.scopedSlotsCompiler==="augmented"){$setScopedSlotsParams("default",{"item":item})}}',
{
scopedSlotsCompiler: 'auto'
}
......@@ -123,7 +123,7 @@ describe('mp:compiler-mp-alipay', () => {
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($scope.props.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",object)}}',
'with(this){if($scope.props.scopedSlotsCompiler==="augmented"){$setScopedSlotsParams("default",object)}}',
{
scopedSlotsCompiler: 'auto'
}
......
......@@ -99,7 +99,7 @@ describe('mp:compiler-mp-baidu', () => {
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($scope.data.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",{"item":item})}}',
'with(this){if($scope.data.scopedSlotsCompiler==="augmented"){$setScopedSlotsParams("default",{"item":item})}}',
{
scopedSlotsCompiler: 'auto'
}
......@@ -107,7 +107,7 @@ describe('mp:compiler-mp-baidu', () => {
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($scope.data.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",object)}}',
'with(this){if($scope.data.scopedSlotsCompiler==="augmented"){$setScopedSlotsParams("default",object)}}',
{
scopedSlotsCompiler: 'auto'
}
......
......@@ -116,7 +116,39 @@ describe('mp:compiler-mp-weixin', () => {
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($scope.data.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",{"item":item})}}',
'with(this){if($scope.data.scopedSlotsCompiler==="augmented"){$setScopedSlotsParams("default",{"item":item})}}',
{
scopedSlotsCompiler: 'auto'
}
)
assertCodegen(
'<view><view v-for="(item,index) in list" :key="index"><slot :item="item"><slot></view></view>',
'<view><block wx:for="{{$root.l0}}" wx:for-item="item" wx:for-index="index" wx:key="index"><view><block wx:if="{{$slots.default}}"><slot></slot><scoped-slots-default item="{{item.$orig}}" class="scoped-ref" bind:__l="__l"></scoped-slots-default></block><block wx:else><slot></slot></block></view></block></view>',
'with(this){var l0=__map(list,function(item,index){var $orig=__get_orig(item);if($scope.data.scopedSlotsCompiler==="augmented"){$setScopedSlotsParams("default",{"item":$orig})}return{$orig:$orig}});$mp.data=Object.assign({},{$root:{l0:l0}})}',
{
scopedSlotsCompiler: 'auto'
}
)
assertCodegen(
'<view><view v-for="(item,index) in list" :key="index"><slot :item="item" :test="test"><slot></view></view>',
'<view><block wx:for="{{$root.l0}}" wx:for-item="item" wx:for-index="index" wx:key="index"><view><block wx:if="{{$slots.default}}"><slot></slot><scoped-slots-default item="{{item.$orig}}" test="{{test}}" class="scoped-ref" bind:__l="__l"></scoped-slots-default></block><block wx:else><slot></slot></block></view></block></view>',
'with(this){var l0=__map(list,function(item,index){var $orig=__get_orig(item);if($scope.data.scopedSlotsCompiler==="augmented"){$setScopedSlotsParams("default",{"item":$orig,"test":test})}return{$orig:$orig}});$mp.data=Object.assign({},{$root:{l0:l0}})}',
{
scopedSlotsCompiler: 'auto'
}
)
assertCodegen(
'<view><view v-for="(item,index) in list" :key="index"><slot :item="item" :test="test()"><slot></view></view>',
'<view><block wx:for="{{$root.l0}}" wx:for-item="item" wx:for-index="index" wx:key="index"><view><block wx:if="{{$slots.default}}"><slot></slot><scoped-slots-default item="{{item.$orig}}" test="{{$root.m0}}" class="scoped-ref" bind:__l="__l"></scoped-slots-default></block><block wx:else><slot></slot></block></view></block></view>',
'with(this){var m0=test();var l0=__map(list,function(item,index){var $orig=__get_orig(item);if($scope.data.scopedSlotsCompiler==="augmented"){$setScopedSlotsParams("default",{"item":$orig,"test":m0})}return{$orig:$orig}});$mp.data=Object.assign({},{$root:{m0:m0,l0:l0}})}',
{
scopedSlotsCompiler: 'auto'
}
)
assertCodegen(
'<view><view v-for="(item,index) in list" :key="index"><slot :item="item" :test="test()+item"><slot></view></view>',
'<view><block wx:for="{{$root.l0}}" wx:for-item="item" wx:for-index="index" wx:key="index"><view><block wx:if="{{$slots.default}}"><slot></slot><scoped-slots-default item="{{item.$orig}}" test="{{$root.m0+item.$orig}}" class="scoped-ref" bind:__l="__l"></scoped-slots-default></block><block wx:else><slot></slot></block></view></block></view>',
'with(this){var m0=test();var l0=__map(list,function(item,index){var $orig=__get_orig(item);if($scope.data.scopedSlotsCompiler==="augmented"){$setScopedSlotsParams("default",{"item":$orig,"test":m0+$orig})}return{$orig:$orig}});$mp.data=Object.assign({},{$root:{m0:m0,l0:l0}})}',
{
scopedSlotsCompiler: 'auto'
}
......@@ -124,7 +156,7 @@ describe('mp:compiler-mp-weixin', () => {
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($scope.data.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",{"item":$root.m0})}}',
'with(this){var m0=getValue(item);$mp.data=Object.assign({},{$root:{m0:m0}});if($scope.data.scopedSlotsCompiler==="augmented"){$setScopedSlotsParams("default",{"item":m0})}}',
{
scopedSlotsCompiler: 'auto'
}
......@@ -132,7 +164,7 @@ describe('mp:compiler-mp-weixin', () => {
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($scope.data.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",object)}}',
'with(this){if($scope.data.scopedSlotsCompiler==="augmented"){$setScopedSlotsParams("default",object)}}',
{
scopedSlotsCompiler: 'auto'
}
......@@ -167,7 +199,7 @@ describe('mp:compiler-mp-weixin', () => {
assertCodegen(
'<view><slot :item="item"><slot></view>',
'<view><block wx:if="{{$slots.default}}"><slot></slot></block><block wx:else><slot></slot></block></view>',
'with(this){$setScopedSlotsParams("default",{"item":item})}',
'with(this){{$setScopedSlotsParams("default",{"item":item})}}',
{
scopedSlotsCompiler: 'augmented'
}
......@@ -175,7 +207,7 @@ describe('mp:compiler-mp-weixin', () => {
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)})}',
'with(this){{$setScopedSlotsParams("default",{"item":getValue(item)})}}',
{
scopedSlotsCompiler: 'augmented'
}
......@@ -183,7 +215,7 @@ describe('mp:compiler-mp-weixin', () => {
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){$setScopedSlotsParams("default",object)}',
'with(this){{$setScopedSlotsParams("default",object)}}',
{
scopedSlotsCompiler: 'augmented'
}
......
......@@ -24,7 +24,8 @@ const {
const {
getInItIfStatement,
getDataExpressionStatement
getDataExpressionStatement,
getRenderSlotStatement
} = require('./statements')
const visitor = require('./visitor')
......@@ -114,22 +115,7 @@ module.exports = function traverse (ast, state) {
}
if (renderSlotStatementArray.length) {
if (state.options.scopedSlotsCompiler === 'auto') {
const node = t.ifStatement(
t.binaryExpression('===',
t.memberExpression(t.memberExpression(t.identifier('$scope'), 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)
}
blockStatementBody.push(getRenderSlotStatement(state, renderSlotStatementArray))
}
reIdentifier(identifierArray)
......
......@@ -135,7 +135,8 @@ module.exports = function traverseRenderList (path, state) {
forIndex,
forExtra: getForExtra(forItem, forIndex, path, state),
propertyArray: [],
declarationArray: []
declarationArray: [],
renderSlotStatementArray: []
}
const forState = {
......@@ -149,13 +150,14 @@ module.exports = function traverseRenderList (path, state) {
propertyArray: [],
declarationArray: [],
computedProperty: {},
initExpressionStatementArray: state.initExpressionStatementArray
initExpressionStatementArray: state.initExpressionStatementArray,
renderSlotStatementArray: state.renderSlotStatementArray
}
functionExpression.traverse(require('./visitor'), forState)
const forPath = path.get('arguments.0')
if (forStateScoped.propertyArray.length) {
if (forStateScoped.propertyArray.length || forStateScoped.renderSlotStatementArray.length) {
// for => map
forPath.replaceWith(
getMemberExpr(
......@@ -165,9 +167,11 @@ module.exports = function traverseRenderList (path, state) {
forPath.node,
forStateScoped.propertyArray,
forStateScoped.declarationArray,
forStateScoped.renderSlotStatementArray,
[], // eventPropertyArray
forItem,
forIndex
forIndex,
state
),
forState
)
......
......@@ -15,7 +15,7 @@ module.exports = function getRenderSlot (path, state) {
const newProperties = []
propertiesPath.forEach(path => {
const properties = path.get('key').isStringLiteral({ value: 'SLOT_DEFAULT' }) ? oldProperties : newProperties
properties.push(state.options.scopedSlotsCompiler === 'auto' ? path.node : t.cloneDeep(path.node))
properties.push(state.options.scopedSlotsCompiler === 'auto' ? path.node : t.cloneNode(path.node, true))
})
if (!newProperties.length) {
return
......@@ -29,7 +29,10 @@ module.exports = function getRenderSlot (path, state) {
}
}
if (valueNode) {
state.renderSlotStatementArray.push(t.expressionStatement(t.callExpression(t.identifier('$setScopedSlotsParams'), [t.stringLiteral(name.node.value), valueNode])))
const scoped = state.scoped
// TODO 判断是否包含作用域内变量
const renderSlotStatementArray = scoped && scoped.length ? scoped[scoped.length - 1].renderSlotStatementArray : state.renderSlotStatementArray
renderSlotStatementArray.push(t.expressionStatement(t.callExpression(t.identifier('$setScopedSlotsParams'), [t.stringLiteral(name.node.value), valueNode])))
}
// TODO 组件嵌套
}
......@@ -4,7 +4,9 @@ const {
VAR_MP,
VAR_ROOT,
VAR_ORIGINAL,
INTERNAL_GET_ORIG
INTERNAL_GET_ORIG,
IDENTIFIER_METHOD,
IDENTIFIER_FILTER
} = require('../../constants')
/**
* e0=e=>count++
......@@ -31,6 +33,53 @@ function getInItIfStatement (expressionStatementArray) {
)
}
function getRenderSlotStatement (state, renderSlotStatementArray, forItem) {
function cloneNode (node) {
if (Array.isArray(node)) {
return node.map(function (item) {
return cloneNode(item)
})
} else if (typeof node === 'object') {
if (!node) {
return node
}
if (t.isMemberExpression(node)) { // 纠正被处理过的对象
const name = node.object.name
// identifier 使用原值以被后续修改
if ((name === VAR_ROOT || name === forItem) && t.isIdentifier(node.property) && [IDENTIFIER_METHOD, IDENTIFIER_FILTER].includes(node.property.name)) {
return node.property
}
} else if (t.isIdentifier(node, { name: forItem })) { // 预处理 forItem
return t.identifier(VAR_ORIGINAL)
}
const target = Object.create(node)
Object.keys(node).forEach(function (key) {
target[key] = cloneNode(node[key])
})
return target
} else {
return node
}
}
renderSlotStatementArray.forEach(renderSlotStatement => {
const argument = renderSlotStatement.expression.arguments[1]
if (t.isObjectExpression(argument)) {
// 克隆以避免影响模板
argument.properties = cloneNode(argument.properties)
}
})
const blockStatement = t.blockStatement(renderSlotStatementArray)
if (state.options.scopedSlotsCompiler === 'auto') {
return t.ifStatement(
t.binaryExpression('===',
t.memberExpression(t.memberExpression(t.identifier('$scope'), t.identifier(state.options.platform.name === 'mp-alipay' ? 'props' : 'data')), t.identifier('scopedSlotsCompiler')), t.stringLiteral('augmented')
),
blockStatement
)
}
return blockStatement
}
/**
* items.map(function(item,index){return {}})
*/
......@@ -38,9 +87,11 @@ function getMapCallExpression (
object,
objectPropertyArray,
declarationArray,
renderSlotStatementArray,
eventPropertyArray,
forItem,
forIndex
forIndex,
state
) {
const blockStatement = []
// var $orgi = __get_orig(forItem)
......@@ -49,24 +100,28 @@ function getMapCallExpression (
t.identifier(forItem)
]))
]))
if (declarationArray.length) {
declarationArray.forEach(declaration => {
blockStatement.push(declaration)
})
blockStatement.push(t.returnStatement(
// return {$orgi:$orgi}
t.objectExpression(
[
t.objectProperty(
t.identifier(VAR_ORIGINAL),
t.identifier(VAR_ORIGINAL)
)
].concat(objectPropertyArray)
)
))
}
if (renderSlotStatementArray.length) {
blockStatement.push(getRenderSlotStatement(state, renderSlotStatementArray, forItem))
}
blockStatement.push(t.returnStatement(
// return {$orgi:$orgi}
t.objectExpression(
[
t.objectProperty(
t.identifier(VAR_ORIGINAL),
t.identifier(VAR_ORIGINAL)
)
].concat(objectPropertyArray)
)
))
const params = [t.identifier(forItem)]
if (forIndex) {
params.push(t.identifier(forIndex))
......@@ -119,5 +174,6 @@ module.exports = {
getInItIfStatement,
getMapCallExpression,
getDataExpressionStatement,
getEventExpressionStatement
getEventExpressionStatement,
getRenderSlotStatement
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册