From 9f03c2adb24d699b21f28e5061a168264fb01bf5 Mon Sep 17 00:00:00 2001 From: fxy060608 Date: Wed, 12 Oct 2022 13:26:05 +0800 Subject: [PATCH] fix(mp): scoped slots with attribute node (question/153150) and slot in v-for (question/155008) --- packages/uni-cloud/lib/uni.plugin.js | 5 +- .../__tests__/scopedSlot.spec.ts | 7 ++ .../uni-mp-compiler/__tests__/slot.spec.ts | 7 ++ .../src/transforms/transformSlot.ts | 73 ++++++++++++++----- 4 files changed, 71 insertions(+), 21 deletions(-) diff --git a/packages/uni-cloud/lib/uni.plugin.js b/packages/uni-cloud/lib/uni.plugin.js index b7922a1b5..60b7b6ebf 100644 --- a/packages/uni-cloud/lib/uni.plugin.js +++ b/packages/uni-cloud/lib/uni.plugin.js @@ -36,7 +36,7 @@ function uniCloudPlugin() { if (process.env.UNI_PLATFORM === 'h5' && !process.env.UNI_SUB_PLATFORM && process.env.NODE_ENV === 'production') { - console.warn('发布H5,需要在uniCloud后台操作,绑定安全域名,否则会因为跨域问题而无法访问。教程参考:https://uniapp.dcloud.net.cn/uniCloud/publish.html#useinh5'); + console.warn('发布到web端需要在uniCloud后台操作,绑定安全域名,否则会因为跨域问题而无法访问。教程参考:https://uniapp.dcloud.net.cn/uniCloud/publish.html#useinh5'); } return {}; }, @@ -55,8 +55,7 @@ function uniCloudPlugin() { closeBundle() { if (process.env.UNI_PLATFORM === 'h5' && !process.env.UNI_SSR_CLIENT) { console.log(); - console.log('欢迎将H5站部署到uniCloud前端网页托管平台,高速、免费、安全、省心,详见:'); - console.log('https://uniapp.dcloud.io/uniCloud/hosting'); + console.log('欢迎将web站点部署到uniCloud前端网页托管平台,高速、免费、安全、省心,详见:https://uniapp.dcloud.io/uniCloud/hosting'); } }, }; diff --git a/packages/uni-mp-compiler/__tests__/scopedSlot.spec.ts b/packages/uni-mp-compiler/__tests__/scopedSlot.spec.ts index 5fd09578d..275f2d060 100644 --- a/packages/uni-mp-compiler/__tests__/scopedSlot.spec.ts +++ b/packages/uni-mp-compiler/__tests__/scopedSlot.spec.ts @@ -2,6 +2,13 @@ import { assert } from './testUtils' describe('compiler: transform scoped slots', () => { test('basic', () => { + assert( + ``, + ``, + `(_ctx, _cache) => { + return { a: _r("d", { data: "123" }) } +}` + ) assert( ``, ``, diff --git a/packages/uni-mp-compiler/__tests__/slot.spec.ts b/packages/uni-mp-compiler/__tests__/slot.spec.ts index 66825f22a..1fa41d7c3 100644 --- a/packages/uni-mp-compiler/__tests__/slot.spec.ts +++ b/packages/uni-mp-compiler/__tests__/slot.spec.ts @@ -37,6 +37,13 @@ describe('compiler: transform slot', () => { ``, `(_ctx, _cache) => { return { a: _f(3, (item, index, i0) => { return { a: _d('title' + index + '-' + i0), b: _r(_d('title' + index), { content: { name: 'name' + index } }, i0), c: index }; }) } +}` + ) + assert( + ``, + ``, + `(_ctx, _cache) => { + return { a: _f(3, (item, index, i0) => { return { a: _d(item.slot), b: _r(_d(item.slot), { content: { name: 'name' + index } }, i0), c: index }; }) } }` ) }) diff --git a/packages/uni-mp-compiler/src/transforms/transformSlot.ts b/packages/uni-mp-compiler/src/transforms/transformSlot.ts index b19400f4d..23e873618 100644 --- a/packages/uni-mp-compiler/src/transforms/transformSlot.ts +++ b/packages/uni-mp-compiler/src/transforms/transformSlot.ts @@ -19,12 +19,14 @@ import { RENDER_SLOT } from '../runtimeHelpers' import { genExpr } from '../codegen' import { isScopedSlotVFor, isVForScope, TransformContext } from '../transform' import { processProps } from './transformElement' -import { removeAttribute, rewriteExpression } from './utils' +import { isReferencedByIds, removeAttribute, rewriteExpression } from './utils' import { createAttributeNode, createBindDirectiveNode, + isDirectiveNode, } from '@dcloudio/uni-cli-shared' import { DYNAMIC_SLOT } from '..' +import { parseExpr } from '../ast' export function rewriteSlot(node: SlotOutletNode, context: TransformContext) { let slotName: string | ExpressionNode = `"${SLOT_DEFAULT_NAME}"` @@ -53,13 +55,21 @@ export function rewriteSlot(node: SlotOutletNode, context: TransformContext) { } if (p.name === 'bind' && isStaticArgOf(p.arg, 'name')) { if (p.exp) { - const slotKey = parseScopedSlotKey(context) - // renderSlot 第三个参数已经传了 slotKey slotName = createCompoundExpression([ context.helperString(DYNAMIC_SLOT) + '(', p.exp, ')', ]) + let slotKey + debugger + const keys = parseVForKeyAlias(context) + if (keys.length) { + const babelNode = parseExpr(p.exp, context) + // 在 v-for 中,判断是否插槽名使用 v-for 的 key 变量 + if (babelNode && isReferencedByIds(babelNode, keys)) { + slotKey = parseScopedSlotKey(context) + } + } p.exp = rewriteExpression( createCompoundExpression([ context.helperString(DYNAMIC_SLOT) + '(', @@ -90,10 +100,8 @@ export function rewriteSlot(node: SlotOutletNode, context: TransformContext) { processProps(node, context, nonNameProps) const properties: string[] = [] nonNameProps.forEach((prop) => { - if (prop.type === NodeTypes.DIRECTIVE && prop.name === 'bind') { - const property = transformProperty(prop, context) - property && properties.push(property) - } + const property = transformProperty(prop, context) + property && properties.push(property) }) if (properties.length) { transformScopedSlotName(node, context) @@ -174,7 +182,19 @@ function createScopedSlotDirectiveNode( return dir } -function parseScopedSlotKey(context: TransformContext) { +function parseVForKeyAlias(context: TransformContext) { + let { currentScope } = context + const keys: string[] = [] + while (currentScope) { + if (isVForScope(currentScope) && !isScopedSlotVFor(currentScope)) { + keys.push(currentScope.keyAlias) + } + currentScope = currentScope.parent! + } + return keys +} + +function parseVForIndexes(context: TransformContext) { let { currentScope } = context const indexes: string[] = [] while (currentScope) { @@ -183,22 +203,39 @@ function parseScopedSlotKey(context: TransformContext) { } currentScope = currentScope.parent! } + return indexes +} + +function parseSlotKeyByVForIndexes(indexes: string[]) { + return indexes.reverse().join(`+'-'+`) +} + +function parseScopedSlotKey(context: TransformContext) { + const indexes = parseVForIndexes(context) const inFor = !!indexes.length if (inFor) { - return indexes.reverse().join(`+'-'+`) + return parseSlotKeyByVForIndexes(indexes) } } -function transformProperty(dir: DirectiveNode, context: TransformContext) { - if (!dir.arg || !dir.exp) { - return - } +function transformProperty( + dir: DirectiveNode | AttributeNode, + _: TransformContext +) { + if (isDirectiveNode(dir)) { + if (!dir.arg || !dir.exp) { + return + } - const isStaticArg = - dir.arg.type === NodeTypes.SIMPLE_EXPRESSION && dir.arg.isStatic + const isStaticArg = + dir.arg.type === NodeTypes.SIMPLE_EXPRESSION && dir.arg.isStatic - if (isStaticArg) { - return `${(dir.arg as SimpleExpressionNode).content}:${genExpr(dir.exp)}` + if (isStaticArg) { + return `${(dir.arg as SimpleExpressionNode).content}:${genExpr(dir.exp)}` + } + return `[${genExpr(dir.arg)}||'']:${genExpr(dir.exp)}` + } + if (dir.value) { + return `${dir.name}:${genExpr(dir.value)}` } - return `[${genExpr(dir.arg)}||'']:${genExpr(dir.exp)}` } -- GitLab