diff --git a/packages/uni-template-compiler/__tests__/compiler-mp-alipay.spec.js b/packages/uni-template-compiler/__tests__/compiler-mp-alipay.spec.js
index 4541914ab2e6454da178ee28c06e45d8465d609c..355f816b5e7090a440d0ab1e5552bfff53f1c1f7 100644
--- a/packages/uni-template-compiler/__tests__/compiler-mp-alipay.spec.js
+++ b/packages/uni-template-compiler/__tests__/compiler-mp-alipay.spec.js
@@ -87,6 +87,49 @@ describe('mp:compiler-mp-alipay', () => {
)
})
+ it('generate scoped slot with scopedSlotsCompiler: auto', () => {
+ assertCodegen(
+ '{{item}}',
+ '{{__SCOPED__.item}}',
+ 'with(this){}',
+ {
+ scopedSlotsCompiler: 'auto'
+ }
+ )
+ assertCodegen(
+ '{{getValue(item)}}',
+ '{{$root.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'
+ }
+ )
+ assertCodegen(
+ '{{getValue(item.text)}}',
+ '{{$root.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'
+ }
+ )
+ assertCodegen(
+ '',
+ '',
+ 'with(this){if($mp.component.props.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",{"item":item})}}',
+ {
+ scopedSlotsCompiler: 'auto'
+ }
+ )
+ assertCodegen(
+ '',
+ '',
+ 'with(this){if($mp.component.props.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",object)}}',
+ {
+ scopedSlotsCompiler: 'auto'
+ }
+ )
+ })
+
it('generate class binding', () => {
assertCodegen(
'
1
',
diff --git a/packages/uni-template-compiler/__tests__/compiler-mp-baidu.spec.js b/packages/uni-template-compiler/__tests__/compiler-mp-baidu.spec.js
index addfc54e7206accfa1dfb68c85ea3f039444f813..d2c9c7cd0de7677f7e4c84d4760655307d3300b9 100644
--- a/packages/uni-template-compiler/__tests__/compiler-mp-baidu.spec.js
+++ b/packages/uni-template-compiler/__tests__/compiler-mp-baidu.spec.js
@@ -65,6 +65,49 @@ describe('mp:compiler-mp-baidu', () => {
)
})
+ it('generate scoped slot with scopedSlotsCompiler: auto', () => {
+ assertCodegen(
+ '{{item}}',
+ '{{item}}',
+ 'with(this){}',
+ {
+ scopedSlotsCompiler: 'auto'
+ }
+ )
+ assertCodegen(
+ '{{getValue(item)}}',
+ '{{$root.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'
+ }
+ )
+ assertCodegen(
+ '{{getValue(item.text)}}',
+ '{{$root.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'
+ }
+ )
+ assertCodegen(
+ '',
+ '',
+ 'with(this){if($mp.component.data.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",{"item":item})}}',
+ {
+ scopedSlotsCompiler: 'auto'
+ }
+ )
+ assertCodegen(
+ '',
+ '',
+ 'with(this){if($mp.component.data.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",object)}}',
+ {
+ scopedSlotsCompiler: 'auto'
+ }
+ )
+ })
+
it('generate vue id', () => {
assertCodegen(
'',
diff --git a/packages/uni-template-compiler/__tests__/compiler-mp-weixin.spec.js b/packages/uni-template-compiler/__tests__/compiler-mp-weixin.spec.js
index efa48612dac830a7185da76f0c784b2316f40554..c8e413faeebcbf62e1c40962cafc05e0fdc6aef5 100644
--- a/packages/uni-template-compiler/__tests__/compiler-mp-weixin.spec.js
+++ b/packages/uni-template-compiler/__tests__/compiler-mp-weixin.spec.js
@@ -82,13 +82,64 @@ describe('mp:compiler-mp-weixin', () => {
)
})
- it('generate scoped slot with filter', () => {
+ it('generate scoped slot with scopedSlotsCompiler: auto', () => {
+ assertCodegen(
+ '{{item}}',
+ '',
+ 'with(this){}',
+ {
+ scopedSlotsCompiler: 'auto'
+ }
+ )
+ assertCodegen(
+ '{{getValue(item)}}',
+ '{{$root.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'
+ }
+ )
+ assertCodegen(
+ '{{getValue(item.text)}}',
+ '{{$root.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'
+ }
+ )
+ assertCodegen(
+ '',
+ '',
+ 'with(this){if($mp.component.data.scopedSlotsCompiler==="augmented"){const $root=$mp.data.$root;$setScopedSlotsParams("default",{"item":item})}}',
+ {
+ scopedSlotsCompiler: 'auto'
+ }
+ )
+ assertCodegen(
+ '',
+ '',
+ '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(
+ '',
+ '',
+ '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(
'{{getValue(item)}}',
'{{$root.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}})}',
{
- betterScopedSlots: true
+ scopedSlotsCompiler: 'augmented'
}
)
assertCodegen(
@@ -96,7 +147,7 @@ describe('mp:compiler-mp-weixin', () => {
'{{$root.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}})}',
{
- betterScopedSlots: true
+ scopedSlotsCompiler: 'augmented'
}
)
assertCodegen(
@@ -104,7 +155,15 @@ describe('mp:compiler-mp-weixin', () => {
'',
'with(this){$setScopedSlotsParams("default",{"item":item})}',
{
- betterScopedSlots: true
+ scopedSlotsCompiler: 'augmented'
+ }
+ )
+ assertCodegen(
+ '',
+ '',
+ 'with(this){$setScopedSlotsParams("default",{"item":getValue(item)})}',
+ {
+ scopedSlotsCompiler: 'augmented'
}
)
assertCodegen(
@@ -112,7 +171,7 @@ describe('mp:compiler-mp-weixin', () => {
'',
'with(this){$setScopedSlotsParams("default",object)}',
{
- betterScopedSlots: true
+ scopedSlotsCompiler: 'augmented'
}
)
})
diff --git a/packages/uni-template-compiler/lib/script/traverse/index.js b/packages/uni-template-compiler/lib/script/traverse/index.js
index c293ca116e86808a17ef7e9c7d50d6a3ff1e4814..506c880b5ca0bda0f27851a855e7065a481ae361 100644
--- a/packages/uni-template-compiler/lib/script/traverse/index.js
+++ b/packages/uni-template-compiler/lib/script/traverse/index.js
@@ -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)
diff --git a/packages/uni-template-compiler/lib/script/traverse/render-slot.js b/packages/uni-template-compiler/lib/script/traverse/render-slot.js
index 4c82bd56be6931408d6ce4952e424187d665a3b9..abb541e821252d0842a7446bfe3706593b548f2b 100644
--- a/packages/uni-template-compiler/lib/script/traverse/render-slot.js
+++ b/packages/uni-template-compiler/lib/script/traverse/render-slot.js
@@ -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
}
diff --git a/packages/uni-template-compiler/lib/script/traverse/resolve-scoped-slots.js b/packages/uni-template-compiler/lib/script/traverse/resolve-scoped-slots.js
index 16ea38e0f415a7d3bbf62e80214ed8b28e18c085..f85252ea9513737217fbc981ba15aa5ceb5fde0b 100644
--- a/packages/uni-template-compiler/lib/script/traverse/resolve-scoped-slots.js
+++ b/packages/uni-template-compiler/lib/script/traverse/resolve-scoped-slots.js
@@ -1,9 +1,29 @@
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'
+ }
}
}
diff --git a/packages/uni-template-compiler/lib/script/traverse/visitor.js b/packages/uni-template-compiler/lib/script/traverse/visitor.js
index 721cd334060aebe60236d4f02e10baa77090c30c..e653a594fab4e7c9dbf3975e285cd380cd085e4e 100644
--- a/packages/uni-template-compiler/lib/script/traverse/visitor.js
+++ b/packages/uni-template-compiler/lib/script/traverse/visitor.js
@@ -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) {
diff --git a/packages/uni-template-compiler/lib/template/traverse.js b/packages/uni-template-compiler/lib/template/traverse.js
index fd700937121dc4a6358e0aae943677e71cbb0c66..e2af15127e304a74261ea00fda1c0f07f7016e37 100644
--- a/packages/uni-template-compiler/lib/template/traverse.js
+++ b/packages/uni-template-compiler/lib/template/traverse.js
@@ -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'])) {
diff --git a/packages/vue-cli-plugin-uni/lib/env.js b/packages/vue-cli-plugin-uni/lib/env.js
index 4c0ae123245cb36302ef7b5d13d78a2d729b37bb..ce235e803440d97f6fbb682709a11fa3c5c5da9d 100644
--- a/packages/vue-cli-plugin-uni/lib/env.js
+++ b/packages/vue-cli-plugin-uni/lib/env.js
@@ -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 ||
diff --git a/packages/webpack-uni-mp-loader/lib/template.js b/packages/webpack-uni-mp-loader/lib/template.js
index 11ff5b8298fb6c98e04ea274c8f81f1b2ea36ef8..68f05ea924c114fcb00d0d4c3e7dbb48bd8f0d09 100644
--- a/packages/webpack-uni-mp-loader/lib/template.js
+++ b/packages/webpack-uni-mp-loader/lib/template.js
@@ -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,
diff --git a/src/core/runtime/wrapper/util.js b/src/core/runtime/wrapper/util.js
index c91dfb17a33fb47174b981f2b0b31ce4083a2f51..28eaaecf78ec98ec8be562cfa942c7aeae88ed89 100644
--- a/src/core/runtime/wrapper/util.js
+++ b/src/core/runtime/wrapper/util.js
@@ -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]
}
-}
+}