fix(compiler-core): fix prefixing for <template v-for> key expressions

fix #2085
This commit is contained in:
Evan You 2020-09-14 17:04:27 -04:00
parent a32870a8f6
commit be946ea549
2 changed files with 77 additions and 8 deletions

View File

@ -582,6 +582,61 @@ describe('compiler: v-for', () => {
] ]
}) })
}) })
test('element v-for key expression prefixing', () => {
const {
node: { codegenNode }
} = parseWithForTransform(
'<div v-for="item in items" :key="itemKey(item)">test</div>',
{ prefixIdentifiers: true }
)
const innerBlock = codegenNode.children.arguments[1].returns
expect(innerBlock).toMatchObject({
type: NodeTypes.VNODE_CALL,
tag: `"div"`,
props: createObjectMatcher({
key: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [
// should prefix outer scope references
{ content: `_ctx.itemKey` },
`(`,
// should NOT prefix in scope variables
{ content: `item` },
`)`
]
}
})
})
})
// #2085
test('template v-for key expression prefixing', () => {
const {
node: { codegenNode }
} = parseWithForTransform(
'<template v-for="item in items" :key="itemKey(item)">test</template>',
{ prefixIdentifiers: true }
)
const innerBlock = codegenNode.children.arguments[1].returns
expect(innerBlock).toMatchObject({
type: NodeTypes.VNODE_CALL,
tag: FRAGMENT,
props: createObjectMatcher({
key: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [
// should prefix outer scope references
{ content: `_ctx.itemKey` },
`(`,
// should NOT prefix in scope variables
{ content: `item` },
`)`
]
}
})
})
})
}) })
describe('codegen', () => { describe('codegen', () => {

View File

@ -54,6 +54,27 @@ export const transformFor = createStructuralDirectiveTransform(
forNode.source forNode.source
]) as ForRenderListExpression ]) as ForRenderListExpression
const keyProp = findProp(node, `key`) const keyProp = findProp(node, `key`)
const keyProperty = keyProp
? createObjectProperty(
`key`,
keyProp.type === NodeTypes.ATTRIBUTE
? createSimpleExpression(keyProp.value!.content, true)
: keyProp.exp!
)
: null
if (!__BROWSER__ && context.prefixIdentifiers && keyProperty) {
// #2085 process :key expression needs to be processed in order for it
// to behave consistently for <template v-for> and <div v-for>.
// In the case of `<template v-for>`, the node is discarded and never
// traversed so its key expression won't be processed by the normal
// transforms.
keyProperty.value = processExpression(
keyProperty.value as SimpleExpressionNode,
context
)
}
const isStableFragment = const isStableFragment =
forNode.source.type === NodeTypes.SIMPLE_EXPRESSION && forNode.source.type === NodeTypes.SIMPLE_EXPRESSION &&
forNode.source.isConstant forNode.source.isConstant
@ -108,14 +129,7 @@ export const transformFor = createStructuralDirectiveTransform(
isSlotOutlet(node.children[0]) isSlotOutlet(node.children[0])
? (node.children[0] as SlotOutletNode) // api-extractor somehow fails to infer this ? (node.children[0] as SlotOutletNode) // api-extractor somehow fails to infer this
: null : null
const keyProperty = keyProp
? createObjectProperty(
`key`,
keyProp.type === NodeTypes.ATTRIBUTE
? createSimpleExpression(keyProp.value!.content, true)
: keyProp.exp!
)
: null
if (slotOutlet) { if (slotOutlet) {
// <slot v-for="..."> or <template v-for="..."><slot/></template> // <slot v-for="..."> or <template v-for="..."><slot/></template>
childBlock = slotOutlet.codegenNode as RenderSlotCall childBlock = slotOutlet.codegenNode as RenderSlotCall