mirror of https://github.com/vuejs/core.git
fix(compiler-core): force dynamic slots when slot referencing scope vars (#9427)
close #9380
This commit is contained in:
parent
15fc75f403
commit
99d54b28b4
|
@ -478,7 +478,10 @@ describe('compiler: transform component slots', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should only force dynamic slots when actually using scope vars w/ prefixIdentifiers: true', () => {
|
test('should only force dynamic slots when actually using scope vars w/ prefixIdentifiers: true', () => {
|
||||||
function assertDynamicSlots(template: string, shouldForce: boolean) {
|
function assertDynamicSlots(
|
||||||
|
template: string,
|
||||||
|
expectedPatchFlag?: PatchFlags,
|
||||||
|
) {
|
||||||
const { root } = parseWithSlots(template, { prefixIdentifiers: true })
|
const { root } = parseWithSlots(template, { prefixIdentifiers: true })
|
||||||
let flag: any
|
let flag: any
|
||||||
if (root.children[0].type === NodeTypes.FOR) {
|
if (root.children[0].type === NodeTypes.FOR) {
|
||||||
|
@ -491,8 +494,8 @@ describe('compiler: transform component slots', () => {
|
||||||
.children[0] as ComponentNode
|
.children[0] as ComponentNode
|
||||||
flag = (innerComp.codegenNode as VNodeCall).patchFlag
|
flag = (innerComp.codegenNode as VNodeCall).patchFlag
|
||||||
}
|
}
|
||||||
if (shouldForce) {
|
if (expectedPatchFlag) {
|
||||||
expect(flag).toBe(PatchFlags.DYNAMIC_SLOTS)
|
expect(flag).toBe(expectedPatchFlag)
|
||||||
} else {
|
} else {
|
||||||
expect(flag).toBeUndefined()
|
expect(flag).toBeUndefined()
|
||||||
}
|
}
|
||||||
|
@ -502,14 +505,13 @@ describe('compiler: transform component slots', () => {
|
||||||
`<div v-for="i in list">
|
`<div v-for="i in list">
|
||||||
<Comp v-slot="bar">foo</Comp>
|
<Comp v-slot="bar">foo</Comp>
|
||||||
</div>`,
|
</div>`,
|
||||||
false,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
assertDynamicSlots(
|
assertDynamicSlots(
|
||||||
`<div v-for="i in list">
|
`<div v-for="i in list">
|
||||||
<Comp v-slot="bar">{{ i }}</Comp>
|
<Comp v-slot="bar">{{ i }}</Comp>
|
||||||
</div>`,
|
</div>`,
|
||||||
true,
|
PatchFlags.DYNAMIC_SLOTS,
|
||||||
)
|
)
|
||||||
|
|
||||||
// reference the component's own slot variable should not force dynamic slots
|
// reference the component's own slot variable should not force dynamic slots
|
||||||
|
@ -517,14 +519,13 @@ describe('compiler: transform component slots', () => {
|
||||||
`<Comp v-slot="foo">
|
`<Comp v-slot="foo">
|
||||||
<Comp v-slot="bar">{{ bar }}</Comp>
|
<Comp v-slot="bar">{{ bar }}</Comp>
|
||||||
</Comp>`,
|
</Comp>`,
|
||||||
false,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
assertDynamicSlots(
|
assertDynamicSlots(
|
||||||
`<Comp v-slot="foo">
|
`<Comp v-slot="foo">
|
||||||
<Comp v-slot="bar">{{ foo }}</Comp>
|
<Comp v-slot="bar">{{ foo }}</Comp>
|
||||||
</Comp>`,
|
</Comp>`,
|
||||||
true,
|
PatchFlags.DYNAMIC_SLOTS,
|
||||||
)
|
)
|
||||||
|
|
||||||
// #2564
|
// #2564
|
||||||
|
@ -532,14 +533,35 @@ describe('compiler: transform component slots', () => {
|
||||||
`<div v-for="i in list">
|
`<div v-for="i in list">
|
||||||
<Comp v-slot="bar"><button @click="fn(i)" /></Comp>
|
<Comp v-slot="bar"><button @click="fn(i)" /></Comp>
|
||||||
</div>`,
|
</div>`,
|
||||||
true,
|
PatchFlags.DYNAMIC_SLOTS,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertDynamicSlots(
|
assertDynamicSlots(
|
||||||
`<div v-for="i in list">
|
`<div v-for="i in list">
|
||||||
<Comp v-slot="bar"><button @click="fn()" /></Comp>
|
<Comp v-slot="bar"><button @click="fn()" /></Comp>
|
||||||
</div>`,
|
</div>`,
|
||||||
false,
|
)
|
||||||
|
|
||||||
|
// #9380
|
||||||
|
assertDynamicSlots(
|
||||||
|
`<div v-for="i in list">
|
||||||
|
<Comp :i="i">foo</Comp>
|
||||||
|
</div>`,
|
||||||
|
PatchFlags.PROPS,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertDynamicSlots(
|
||||||
|
`<div v-for="i in list">
|
||||||
|
<Comp v-slot="{ value = i }"><button @click="fn()" /></Comp>
|
||||||
|
</div>`,
|
||||||
|
PatchFlags.DYNAMIC_SLOTS,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertDynamicSlots(
|
||||||
|
`<div v-for="i in list">
|
||||||
|
<Comp v-slot:[i]><button @click="fn()" /></Comp>
|
||||||
|
</div>`,
|
||||||
|
PatchFlags.DYNAMIC_SLOTS,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -131,9 +131,17 @@ export function buildSlots(
|
||||||
// since it likely uses a scope variable.
|
// since it likely uses a scope variable.
|
||||||
let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0
|
let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0
|
||||||
// with `prefixIdentifiers: true`, this can be further optimized to make
|
// with `prefixIdentifiers: true`, this can be further optimized to make
|
||||||
// it dynamic only when the slot actually uses the scope variables.
|
// it dynamic when
|
||||||
|
// 1. the slot arg or exp uses the scope variables.
|
||||||
|
// 2. the slot children use the scope variables.
|
||||||
if (!__BROWSER__ && !context.ssr && context.prefixIdentifiers) {
|
if (!__BROWSER__ && !context.ssr && context.prefixIdentifiers) {
|
||||||
hasDynamicSlots = hasScopeRef(node, context.identifiers)
|
hasDynamicSlots =
|
||||||
|
node.props.some(
|
||||||
|
prop =>
|
||||||
|
isVSlot(prop) &&
|
||||||
|
(hasScopeRef(prop.arg, context.identifiers) ||
|
||||||
|
hasScopeRef(prop.exp, context.identifiers)),
|
||||||
|
) || children.some(child => hasScopeRef(child, context.identifiers))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Check for slot with slotProps on component itself.
|
// 1. Check for slot with slotProps on component itself.
|
||||||
|
|
Loading…
Reference in New Issue