fix(compiler/v-on): handle multiple statements in v-on handler (close #572)
This commit is contained in:
parent
46a793717a
commit
137893a4fd
@ -140,6 +140,22 @@ describe('compiler: transform v-on', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('should handle multiple inline statement', () => {
|
||||||
|
const { node } = parseWithVOn(`<div @click="foo();bar()"/>`)
|
||||||
|
const props = (node.codegenNode as CallExpression)
|
||||||
|
.arguments[1] as ObjectExpression
|
||||||
|
expect(props.properties[0]).toMatchObject({
|
||||||
|
key: { content: `onClick` },
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.COMPOUND_EXPRESSION,
|
||||||
|
// should wrap with `{` for multiple statements
|
||||||
|
// in this case the return value is discarded and the behavior is
|
||||||
|
// consistent with 2.x
|
||||||
|
children: [`$event => {`, { content: `foo();bar()` }, `}`]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
test('inline statement w/ prefixIdentifiers: true', () => {
|
test('inline statement w/ prefixIdentifiers: true', () => {
|
||||||
const { node } = parseWithVOn(`<div @click="foo($event)"/>`, {
|
const { node } = parseWithVOn(`<div @click="foo($event)"/>`, {
|
||||||
prefixIdentifiers: true
|
prefixIdentifiers: true
|
||||||
@ -163,6 +179,31 @@ describe('compiler: transform v-on', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('multiple inline statements w/ prefixIdentifiers: true', () => {
|
||||||
|
const { node } = parseWithVOn(`<div @click="foo($event);bar()"/>`, {
|
||||||
|
prefixIdentifiers: true
|
||||||
|
})
|
||||||
|
const props = (node.codegenNode as CallExpression)
|
||||||
|
.arguments[1] as ObjectExpression
|
||||||
|
expect(props.properties[0]).toMatchObject({
|
||||||
|
key: { content: `onClick` },
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.COMPOUND_EXPRESSION,
|
||||||
|
children: [
|
||||||
|
`$event => {`,
|
||||||
|
{ content: `_ctx.foo` },
|
||||||
|
`(`,
|
||||||
|
// should NOT prefix $event
|
||||||
|
{ content: `$event` },
|
||||||
|
`);`,
|
||||||
|
{ content: `_ctx.bar` },
|
||||||
|
`()`,
|
||||||
|
`}`
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
test('should NOT wrap as function if expression is already function expression', () => {
|
test('should NOT wrap as function if expression is already function expression', () => {
|
||||||
const { node } = parseWithVOn(`<div @click="$event => foo($event)"/>`)
|
const { node } = parseWithVOn(`<div @click="$event => foo($event)"/>`)
|
||||||
const props = (node.codegenNode as CallExpression)
|
const props = (node.codegenNode as CallExpression)
|
||||||
|
@ -76,7 +76,9 @@ export function processExpression(
|
|||||||
context: TransformContext,
|
context: TransformContext,
|
||||||
// some expressions like v-slot props & v-for aliases should be parsed as
|
// some expressions like v-slot props & v-for aliases should be parsed as
|
||||||
// function params
|
// function params
|
||||||
asParams: boolean = false
|
asParams = false,
|
||||||
|
// v-on handler values may contain multiple statements
|
||||||
|
asRawStatements = false
|
||||||
): ExpressionNode {
|
): ExpressionNode {
|
||||||
if (!context.prefixIdentifiers || !node.content.trim()) {
|
if (!context.prefixIdentifiers || !node.content.trim()) {
|
||||||
return node
|
return node
|
||||||
@ -100,9 +102,14 @@ export function processExpression(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let ast: any
|
let ast: any
|
||||||
// if the expression is supposed to be used in a function params position
|
// exp needs to be parsed differently:
|
||||||
// we need to parse it differently.
|
// 1. Multiple inline statements (v-on, with presence of `;`): parse as raw
|
||||||
const source = `(${rawExp})${asParams ? `=>{}` : ``}`
|
// exp, but make sure to pad with spaces for consistent ranges
|
||||||
|
// 2. Expressions: wrap with parens (for e.g. object expressions)
|
||||||
|
// 3. Function arguments (v-for, v-slot): place in a function argument position
|
||||||
|
const source = asRawStatements
|
||||||
|
? ` ${rawExp} `
|
||||||
|
: `(${rawExp})${asParams ? `=>{}` : ``}`
|
||||||
try {
|
try {
|
||||||
ast = parseJS(source, { ranges: true })
|
ast = parseJS(source, { ranges: true })
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -59,11 +59,12 @@ export const transformOn: DirectiveTransform = (
|
|||||||
if (exp) {
|
if (exp) {
|
||||||
const isMemberExp = isMemberExpression(exp.content)
|
const isMemberExp = isMemberExpression(exp.content)
|
||||||
const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content))
|
const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content))
|
||||||
|
const hasMultipleStatements = exp.content.includes(`;`)
|
||||||
|
|
||||||
// process the expression since it's been skipped
|
// process the expression since it's been skipped
|
||||||
if (!__BROWSER__ && context.prefixIdentifiers) {
|
if (!__BROWSER__ && context.prefixIdentifiers) {
|
||||||
context.addIdentifiers(`$event`)
|
context.addIdentifiers(`$event`)
|
||||||
exp = processExpression(exp, context)
|
exp = processExpression(exp, context, false, hasMultipleStatements)
|
||||||
context.removeIdentifiers(`$event`)
|
context.removeIdentifiers(`$event`)
|
||||||
// with scope analysis, the function is hoistable if it has no reference
|
// with scope analysis, the function is hoistable if it has no reference
|
||||||
// to scope variables.
|
// to scope variables.
|
||||||
@ -85,9 +86,9 @@ export const transformOn: DirectiveTransform = (
|
|||||||
if (isInlineStatement || (isCacheable && isMemberExp)) {
|
if (isInlineStatement || (isCacheable && isMemberExp)) {
|
||||||
// wrap inline statement in a function expression
|
// wrap inline statement in a function expression
|
||||||
exp = createCompoundExpression([
|
exp = createCompoundExpression([
|
||||||
`$event => (`,
|
`$event => ${hasMultipleStatements ? `{` : `(`}`,
|
||||||
...(exp.type === NodeTypes.SIMPLE_EXPRESSION ? [exp] : exp.children),
|
...(exp.type === NodeTypes.SIMPLE_EXPRESSION ? [exp] : exp.children),
|
||||||
`)`
|
hasMultipleStatements ? `}` : `)`
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user