mirror of https://github.com/vuejs/core.git
feat(compiler-vapor): add getKey function for v-for
This commit is contained in:
parent
8fb01504da
commit
35b78920c4
|
@ -14,7 +14,7 @@ export function render(_ctx) {
|
||||||
_setText(n3, item)
|
_setText(n3, item)
|
||||||
})
|
})
|
||||||
return n2
|
return n2
|
||||||
})
|
}, (item) => (item.id))
|
||||||
return [n1]
|
return [n1]
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -21,7 +21,7 @@ const compileWithVFor = makeCompile({
|
||||||
describe('compiler: v-for', () => {
|
describe('compiler: v-for', () => {
|
||||||
test('basic v-for', () => {
|
test('basic v-for', () => {
|
||||||
const { code, ir, vaporHelpers, helpers } = compileWithVFor(
|
const { code, ir, vaporHelpers, helpers } = compileWithVFor(
|
||||||
`<div v-for="item of items" @click="remove(item)">{{ item }}</div>`,
|
`<div v-for="item of items" :key="item.id" @click="remove(item)">{{ item }}</div>`,
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(code).matchSnapshot()
|
expect(code).matchSnapshot()
|
||||||
|
@ -52,6 +52,10 @@ describe('compiler: v-for', () => {
|
||||||
type: IRNodeTypes.BLOCK_FUNCTION,
|
type: IRNodeTypes.BLOCK_FUNCTION,
|
||||||
templateIndex: 0,
|
templateIndex: 0,
|
||||||
},
|
},
|
||||||
|
keyProperty: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'item.id',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
expect(ir.returns).toEqual([1])
|
expect(ir.returns).toEqual([1])
|
||||||
|
|
|
@ -17,7 +17,7 @@ export function genFor(
|
||||||
context: CodegenContext,
|
context: CodegenContext,
|
||||||
): CodeFragment[] {
|
): CodeFragment[] {
|
||||||
const { call, vaporHelper } = context
|
const { call, vaporHelper } = context
|
||||||
const { source, value, key, render } = oper
|
const { source, value, key, render, keyProperty } = oper
|
||||||
|
|
||||||
const rawValue = value && value.content
|
const rawValue = value && value.content
|
||||||
const rawKey = key && key.content
|
const rawKey = key && key.content
|
||||||
|
@ -34,12 +34,31 @@ export function genFor(
|
||||||
idMap,
|
idMap,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let getKeyFn: CodeFragment[] | false = false
|
||||||
|
if (keyProperty) {
|
||||||
|
const idMap: Record<string, null> = {}
|
||||||
|
if (rawValue) idMap[rawValue] = null
|
||||||
|
if (rawKey) idMap[rawKey] = null
|
||||||
|
const expr = context.withId(
|
||||||
|
() => genExpression(keyProperty, context),
|
||||||
|
idMap,
|
||||||
|
)
|
||||||
|
getKeyFn = [
|
||||||
|
'(',
|
||||||
|
rawValue ? rawValue : rawKey ? '_' : '',
|
||||||
|
rawKey && `, ${rawKey}`,
|
||||||
|
') => (',
|
||||||
|
...expr,
|
||||||
|
')',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
context.genEffect = undefined
|
context.genEffect = undefined
|
||||||
|
|
||||||
return [
|
return [
|
||||||
NEWLINE,
|
NEWLINE,
|
||||||
`const n${oper.id} = `,
|
`const n${oper.id} = `,
|
||||||
...call(vaporHelper('createFor'), sourceExpr, blockFn),
|
...call(vaporHelper('createFor'), sourceExpr, blockFn, getKeyFn),
|
||||||
]
|
]
|
||||||
|
|
||||||
function genEffectInFor(effects: IREffect[]): CodeFragment[] {
|
function genEffectInFor(effects: IREffect[]): CodeFragment[] {
|
||||||
|
|
|
@ -76,6 +76,7 @@ export interface ForIRNode extends BaseIRNode {
|
||||||
value?: SimpleExpressionNode
|
value?: SimpleExpressionNode
|
||||||
key?: SimpleExpressionNode
|
key?: SimpleExpressionNode
|
||||||
index?: SimpleExpressionNode
|
index?: SimpleExpressionNode
|
||||||
|
keyProperty?: SimpleExpressionNode
|
||||||
render: BlockFunctionIRNode
|
render: BlockFunctionIRNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,16 @@
|
||||||
import {
|
import {
|
||||||
type AttributeNode,
|
|
||||||
NodeTypes,
|
NodeTypes,
|
||||||
type SimpleExpressionNode,
|
type SimpleExpressionNode,
|
||||||
createSimpleExpression,
|
createSimpleExpression,
|
||||||
findProp,
|
|
||||||
} from '@vue/compiler-dom'
|
} from '@vue/compiler-dom'
|
||||||
import { EMPTY_EXPRESSION, type NodeTransform } from '../transform'
|
import { EMPTY_EXPRESSION, type NodeTransform } from '../transform'
|
||||||
import { IRNodeTypes, type VaporDirectiveNode } from '../ir'
|
import { IRNodeTypes } from '../ir'
|
||||||
import { normalizeBindShorthand } from './vBind'
|
import { normalizeBindShorthand } from './vBind'
|
||||||
|
import { findProp } from '../utils'
|
||||||
|
|
||||||
export const transformRef: NodeTransform = (node, context) => {
|
export const transformRef: NodeTransform = (node, context) => {
|
||||||
if (node.type !== NodeTypes.ELEMENT) return
|
if (node.type !== NodeTypes.ELEMENT) return
|
||||||
const dir = findProp(node, 'ref', false, true) as
|
const dir = findProp(node, 'ref', false, true)
|
||||||
| VaporDirectiveNode
|
|
||||||
| AttributeNode
|
|
||||||
|
|
||||||
if (!dir) return
|
if (!dir) return
|
||||||
|
|
||||||
let value: SimpleExpressionNode
|
let value: SimpleExpressionNode
|
||||||
|
|
|
@ -35,19 +35,8 @@ export const transformVBind: DirectiveTransform = (dir, node, context) => {
|
||||||
let { exp } = dir
|
let { exp } = dir
|
||||||
const arg = dir.arg!
|
const arg = dir.arg!
|
||||||
|
|
||||||
if (arg.isStatic && isReservedProp(arg.content)) return
|
|
||||||
|
|
||||||
if (!exp) exp = normalizeBindShorthand(arg, context)
|
if (!exp) exp = normalizeBindShorthand(arg, context)
|
||||||
|
|
||||||
let camel = false
|
|
||||||
if (modifiers.includes('camel')) {
|
|
||||||
if (arg.isStatic) {
|
|
||||||
arg.content = camelize(arg.content)
|
|
||||||
} else {
|
|
||||||
camel = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!exp.content.trim()) {
|
if (!exp.content.trim()) {
|
||||||
if (!__BROWSER__) {
|
if (!__BROWSER__) {
|
||||||
// #10280 only error against empty expression in non-browser build
|
// #10280 only error against empty expression in non-browser build
|
||||||
|
@ -60,6 +49,16 @@ export const transformVBind: DirectiveTransform = (dir, node, context) => {
|
||||||
exp = createSimpleExpression('', true, loc)
|
exp = createSimpleExpression('', true, loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg.isStatic && isReservedProp(arg.content)) return
|
||||||
|
let camel = false
|
||||||
|
if (modifiers.includes('camel')) {
|
||||||
|
if (arg.isStatic) {
|
||||||
|
arg.content = camelize(arg.content)
|
||||||
|
} else {
|
||||||
|
camel = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
key: arg,
|
key: arg,
|
||||||
value: exp,
|
value: exp,
|
||||||
|
|
|
@ -18,6 +18,7 @@ import {
|
||||||
type VaporDirectiveNode,
|
type VaporDirectiveNode,
|
||||||
} from '../ir'
|
} from '../ir'
|
||||||
import { extend } from '@vue/shared'
|
import { extend } from '@vue/shared'
|
||||||
|
import { findProp, propToExpression } from '../utils'
|
||||||
|
|
||||||
export const transformVFor = createStructuralDirectiveTransform(
|
export const transformVFor = createStructuralDirectiveTransform(
|
||||||
'for',
|
'for',
|
||||||
|
@ -45,6 +46,8 @@ export function processFor(
|
||||||
|
|
||||||
const { source, value, key, index } = parseResult
|
const { source, value, key, index } = parseResult
|
||||||
|
|
||||||
|
const keyProp = findProp(node, 'key')
|
||||||
|
const keyProperty = keyProp && propToExpression(keyProp)
|
||||||
context.node = node = wrapTemplate(node, ['for'])
|
context.node = node = wrapTemplate(node, ['for'])
|
||||||
context.dynamic.flags |= DynamicFlag.NON_TEMPLATE | DynamicFlag.INSERT
|
context.dynamic.flags |= DynamicFlag.NON_TEMPLATE | DynamicFlag.INSERT
|
||||||
const id = context.reference()
|
const id = context.reference()
|
||||||
|
@ -71,6 +74,7 @@ export function processFor(
|
||||||
value: value as SimpleExpressionNode | undefined,
|
value: value as SimpleExpressionNode | undefined,
|
||||||
key: key as SimpleExpressionNode | undefined,
|
key: key as SimpleExpressionNode | undefined,
|
||||||
index: index as SimpleExpressionNode | undefined,
|
index: index as SimpleExpressionNode | undefined,
|
||||||
|
keyProperty,
|
||||||
render,
|
render,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import {
|
||||||
|
type AttributeNode,
|
||||||
|
type ElementNode,
|
||||||
|
NodeTypes,
|
||||||
|
findProp as _findProp,
|
||||||
|
createSimpleExpression,
|
||||||
|
} from '@vue/compiler-dom'
|
||||||
|
import type { VaporDirectiveNode } from './ir'
|
||||||
|
import { EMPTY_EXPRESSION } from './transform'
|
||||||
|
|
||||||
|
export const findProp = _findProp as (
|
||||||
|
node: ElementNode,
|
||||||
|
name: string,
|
||||||
|
dynamicOnly?: boolean,
|
||||||
|
allowEmpty?: boolean,
|
||||||
|
) => AttributeNode | VaporDirectiveNode | undefined
|
||||||
|
|
||||||
|
export function propToExpression(prop: AttributeNode | VaporDirectiveNode) {
|
||||||
|
return prop.type === NodeTypes.ATTRIBUTE
|
||||||
|
? prop.value
|
||||||
|
? createSimpleExpression(prop.value.content, true, prop.value.loc)
|
||||||
|
: EMPTY_EXPRESSION
|
||||||
|
: prop.exp
|
||||||
|
}
|
Loading…
Reference in New Issue