提交 4f8ad863 编写于 作者: fxy060608's avatar fxy060608

wip(mp): support dynamicSlotNames

上级 e54d1f76
......@@ -4,7 +4,7 @@ describe(`mp-baidu: transform v-for`, () => {
test(`with key`, () => {
assert(
`<view v-for="item in items" :key="item.id"/>`,
`<view s-for="a trackBy item.a" s-for-item="item"/>`,
`<view s-for="item in a trackBy item.a"/>`,
`(_ctx, _cache) => {
return { a: _f(_ctx.items, (item, k0, i0) => { return { a: item.id }; }) }
}`
......@@ -13,7 +13,7 @@ describe(`mp-baidu: transform v-for`, () => {
test(`without key`, () => {
assert(
`<view v-for="item in items"/>`,
`<view s-for="{{a}}" s-for-item="item"/>`,
`<view s-for="item in a"/>`,
`(_ctx, _cache) => {
return { a: _f(_ctx.items, (item, k0, i0) => { return {}; }) }
}`
......
import { assert } from './testUtils'
describe('compiler: transform v-slot', () => {
test('default slot', () => {
assert(
`<custom><template v-slot/></custom>`,
`<custom v-s="{{['default']}}" v-i="2a9ec0b0-0"><view/></custom>`,
`(_ctx, _cache) => {
return {}
}`
)
assert(
`<custom>test</custom>`,
`<custom v-s="{{['default']}}" v-i="2a9ec0b0-0">test</custom>`,
`(_ctx, _cache) => {
return {}
}`
)
})
test('named slots', () => {
assert(
`<custom><template v-slot:header/><template v-slot:default/><template v-slot:footer/></custom>`,
`<custom v-s="{{['header','default','footer']}}" v-i="2a9ec0b0-0"><view slot="header"/><view slot="default"/><view slot="footer"/></custom>`,
`(_ctx, _cache) => {
return {}
}`
)
assert(
`<unicloud-db v-slot:default="{data, loading, error, options}" collection=""><view v-if="error">{{error.message}}</view><view v-else></view></unicloud-db>`,
`<unicloud-db v-s="{{['default']}}" slot="default" collection="" v-i="2a9ec0b0-0"><block s-for="v0 in a trackBy v0.a"><view s-if="{{v0.b}}">{{v0.c}}</view><view s-else></view></block></unicloud-db>`,
`(_ctx, _cache) => {
return { a: _w(({ data, loading, error, options }, s0, i0) => { return _e({ a: s0, b: error }, error ? { c: _t(error.message) } : {}); }, { name: 'default', vueId: '2a9ec0b0-0' }) }
}`
)
})
test('scoped slots', () => {
assert(
`<custom><template v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template></custom>`,
`<custom v-s="{{['default']}}" v-i="2a9ec0b0-0"><view slot="default"><block s-for="slotProps in a trackBy slotProps.a"><view>{{slotProps.b}}</view></block></view></custom>`,
`(_ctx, _cache) => {
return { a: _w((slotProps, s0, i0) => { return { a: s0, b: _t(slotProps.item) }; }, { name: 'default', vueId: '2a9ec0b0-0' }) }
}`
)
})
test('scoped slots + scoped slots', () => {
assert(
`<custom><template v-slot:default="slotProps"><custom1><template v-slot:default="slotProps1">{{ slotProps.item }}{{ slotProps1.item }}</template></custom1></template></custom>`,
`<custom v-s="{{['default']}}" v-i="2a9ec0b0-0"><view slot="default"><block s-for="slotProps in a trackBy slotProps.a"><custom1 v-s="{{['default']}}" v-i="{{slotProps.d}}"><view slot="default"><block s-for="slotProps1 in slotProps.b trackBy slotProps1.a">{{slotProps.c}}{{slotProps1.b}}</block></view></custom1></block></view></custom>`,
`(_ctx, _cache) => {
return { a: _w((slotProps, s0, i0) => { return { a: s0, b: _w((slotProps1, s1, i1) => { return { a: s1, b: _t(slotProps1.item) }; }, { name: 'default', vueId: '2a9ec0b0-1' + '-' + i0 + ',' + '2a9ec0b0-0' }), c: _t(slotProps.item), d: '2a9ec0b0-1' + '-' + i0 + ',' + '2a9ec0b0-0' }; }, { name: 'default', vueId: '2a9ec0b0-0' }) }
}`
)
})
test('v-if + scoped slots', () => {
assert(
`<custom><template v-if="ok" v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template></custom>`,
`<custom v-s="{{['default']}}" v-i="2a9ec0b0-0"><view s-if="{{a}}" slot="default"><block s-for="slotProps in b trackBy slotProps.a"><view>{{slotProps.b}}</view></block></view></custom>`,
`(_ctx, _cache) => {
return _e({ a: _ctx.ok }, _ctx.ok ? { b: _w((slotProps, s0, i0) => { return { a: s0, b: _t(slotProps.item) }; }, { name: 'default', vueId: '2a9ec0b0-0' }) } : {})
}`
)
})
test('v-for + scoped slots', () => {
assert(
`<custom v-for="item in items"><template v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template></custom>`,
`<custom s-for="item in a" v-s="{{['default']}}" v-i="{{item.b}}"><view slot="default"><block s-for="slotProps in item.a trackBy slotProps.a"><view>{{slotProps.b}}</view></block></view></custom>`,
`(_ctx, _cache) => {
return { a: _f(_ctx.items, (item, k0, i0) => { return { a: _w((slotProps, s1, i1) => { return { a: s1, b: _t(slotProps.item) }; }, { name: 'default', vueId: '2a9ec0b0-0' + '-' + i0 }), b: '2a9ec0b0-0' + '-' + i0 }; }) }
}`
)
})
test('v-for + v-for + scoped slots', () => {
assert(
`<view v-for="item in items"><custom v-for="item1 in item.list" :item="item1"><template v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template></custom></view>`,
`<view s-for="item in a"><custom s-for="item1 in item.a" v-s="{{['default']}}" item="{{item1.b}}" v-i="{{item1.c}}"><view slot="default"><block s-for="slotProps in item1.a trackBy slotProps.a"><view>{{slotProps.b}}</view></block></view></custom></view>`,
`(_ctx, _cache) => {
return { a: _f(_ctx.items, (item, k0, i0) => { return { a: _f(item.list, (item1, k1, i1) => { return { a: _w((slotProps, s2, i2) => { return { a: s2, b: _t(slotProps.item) }; }, { name: 'default', vueId: '2a9ec0b0-0' + '-' + i0 + '-' + i1 }), b: item1, c: '2a9ec0b0-0' + '-' + i0 + '-' + i1 }; }) }; }) }
}`
)
})
test('old syntax', () => {
assert(
`<template slot="left"/>`,
`<view slot="left"/>`,
`(_ctx, _cache) => {
return {}
}`
)
})
})
......@@ -41,15 +41,19 @@ const transformFor = (node, context) => {
if (!uniMpCompiler.isForElementNode(node)) {
return;
}
const { vFor, props } = node;
let sourceCode = vFor.valueAlias + ' in ' + vFor.sourceAlias;
const keyProp = uniMpCompiler.findProp(node, 'key', true);
if (keyProp) {
const { exp } = keyProp;
if (exp) {
const key = uniMpCompiler.rewriteExpression(exp, context).content;
node.vFor.sourceCode = `${node.vFor.sourceAlias} trackBy ${key}`;
node.props.splice(node.props.indexOf(keyProp), 1);
sourceCode = sourceCode + ' trackBy ' + key;
props.splice(props.indexOf(keyProp), 1);
}
}
vFor.valueAlias = '';
vFor.sourceCode = sourceCode;
};
/**
......@@ -156,6 +160,7 @@ const miniProgram = {
},
slot: {
fallbackContent: true,
// https://github.com/baidu/san/discussions/601
dynamicSlotNames: false,
},
directive: 's-',
......
......@@ -24,6 +24,7 @@ export const miniProgram: MiniProgramCompilerOptions = {
},
slot: {
fallbackContent: true,
// https://github.com/baidu/san/discussions/601
dynamicSlotNames: false,
},
directive: 's-',
......
......@@ -10,13 +10,17 @@ export const transformFor: NodeTransform = (node, context) => {
if (!isForElementNode(node)) {
return
}
const { vFor, props } = node
let sourceCode = vFor.valueAlias + ' in ' + vFor.sourceAlias
const keyProp = findProp(node, 'key', true)
if (keyProp) {
const { exp } = keyProp as DirectiveNode
if (exp) {
const key = rewriteExpression(exp, context).content
node.vFor.sourceCode = `${node.vFor.sourceAlias} trackBy ${key}`
node.props.splice(node.props.indexOf(keyProp), 1)
sourceCode = sourceCode + ' trackBy ' + key
props.splice(props.indexOf(keyProp), 1)
}
}
vFor.valueAlias = ''
vFor.sourceCode = sourceCode
}
......@@ -72,24 +72,7 @@ export function rewriteSlot(node: SlotOutletNode, context: TransformContext) {
}
})
if (properties.length) {
const slotKey = parseScopedSlotKey(context)
const nameProps = findProp(node, 'name')
if (!nameProps) {
// 生成默认的 default 插槽名
if (slotKey) {
props.push(
createBindDirectiveNode(
'name',
rewriteExpression(
createSimpleExpression('"default-"+' + slotKey),
context
).content
)
)
} else {
props.push(createAttributeNode('name', 'default'))
}
}
const slotKey = transformScopedSlotKey(node, context)
rewriteExpression(
createCompoundExpression([
context.helperString(RENDER_SLOT) + '(',
......@@ -105,6 +88,35 @@ export function rewriteSlot(node: SlotOutletNode, context: TransformContext) {
}
}
function transformScopedSlotKey(
node: SlotOutletNode,
context: TransformContext
) {
if (!context.miniProgram.slot.dynamicSlotNames) {
return
}
const { props } = node
const slotKey = parseScopedSlotKey(context)
const nameProps = findProp(node, 'name')
if (!nameProps) {
// 生成默认的 default 插槽名
if (slotKey) {
props.push(
createBindDirectiveNode(
'name',
rewriteExpression(
createSimpleExpression('"default-"+' + slotKey),
context
).content
)
)
} else {
props.push(createAttributeNode('name', 'default'))
}
}
return slotKey
}
function parseScopedSlotKey(context: TransformContext) {
let { currentScope } = context
const indexs: string[] = []
......
......@@ -194,10 +194,6 @@ function createVForTemplate(
) {
const key = 's' + context.scopes.vFor
const keyProp: DirectiveNode = createBindDirectiveNode('key', key)
const slotProp: DirectiveNode = createBindDirectiveNode(
'slot',
`i${context.scopes.vFor}`
)
const vForProp: DirectiveNode = {
type: NodeTypes.DIRECTIVE,
name: 'for',
......@@ -210,13 +206,17 @@ function createVForTemplate(
})`
),
}
const props = [vForProp, keyProp]
if (context.miniProgram.slot.dynamicSlotNames) {
props.push(createBindDirectiveNode('slot', `i${context.scopes.vFor}`))
}
return {
loc: slotElement.loc,
ns: 0,
tag: 'template',
type: NodeTypes.ELEMENT,
tagType: ElementTypes.TEMPLATE,
props: [vForProp, keyProp, slotProp],
props,
isSelfClosing: false,
codegenNode: undefined,
children: slotElement.children,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册