Skip to content

Commit

Permalink
fix(compiler-core): fix prefixing for <template v-for> key expressions
Browse files Browse the repository at this point in the history
fix #2085
  • Loading branch information
yyx990803 committed Sep 14, 2020
1 parent a32870a commit be946ea
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 8 deletions.
55 changes: 55 additions & 0 deletions packages/compiler-core/__tests__/transforms/vFor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
30 changes: 22 additions & 8 deletions packages/compiler-core/src/transforms/vFor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,27 @@ export const transformFor = createStructuralDirectiveTransform(
forNode.source
]) as ForRenderListExpression
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 =
forNode.source.type === NodeTypes.SIMPLE_EXPRESSION &&
forNode.source.isConstant
Expand Down Expand Up @@ -108,14 +129,7 @@ export const transformFor = createStructuralDirectiveTransform(
isSlotOutlet(node.children[0])
? (node.children[0] as SlotOutletNode) // api-extractor somehow fails to infer this
: null
const keyProperty = keyProp
? createObjectProperty(
`key`,
keyProp.type === NodeTypes.ATTRIBUTE
? createSimpleExpression(keyProp.value!.content, true)
: keyProp.exp!
)
: null

if (slotOutlet) {
// <slot v-for="..."> or <template v-for="..."><slot/></template>
childBlock = slotOutlet.codegenNode as RenderSlotCall
Expand Down

0 comments on commit be946ea

Please sign in to comment.