mirror of https://github.com/vuejs/core.git
fix(compiler-vapor): v-on for component support `$event` argument (#177)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
This commit is contained in:
parent
9e0cd20da0
commit
e640ec6088
|
@ -91,6 +91,17 @@ export function render(_ctx) {
|
|||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: element transform > component > should wrap as function if v-on expression is inline statement 1`] = `
|
||||
"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
|
||||
|
||||
export function render(_ctx) {
|
||||
const n0 = _createComponent(_resolveComponent("Foo"), [{
|
||||
onBar: () => $event => (_ctx.handleBar($event))
|
||||
}], true)
|
||||
return n0
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: element transform > component > static props 1`] = `
|
||||
"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
|
||||
|
||||
|
|
|
@ -364,6 +364,29 @@ describe('compiler: element transform', () => {
|
|||
},
|
||||
])
|
||||
})
|
||||
|
||||
test('should wrap as function if v-on expression is inline statement', () => {
|
||||
const { code, ir } = compileWithElementTransform(
|
||||
`<Foo v-on:bar="handleBar($event)" />`,
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(code).contains(`onBar: () => $event => (_ctx.handleBar($event))`)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: { content: 'bar' },
|
||||
handler: true,
|
||||
values: [{ content: 'handleBar($event)' }],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
test('static props', () => {
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
import { genExpression } from './expression'
|
||||
import { genPropKey } from './prop'
|
||||
import { createSimpleExpression } from '@vue/compiler-dom'
|
||||
import { genEventHandler } from './event'
|
||||
|
||||
// TODO: generate component slots
|
||||
export function genCreateComponent(
|
||||
|
@ -74,9 +75,10 @@ export function genCreateComponent(
|
|||
...props.map(prop => {
|
||||
return [
|
||||
...genPropKey(prop, context),
|
||||
': () => (',
|
||||
...genExpression(prop.values[0], context),
|
||||
')',
|
||||
': ',
|
||||
...(prop.handler
|
||||
? genEventHandler(context, prop.values[0])
|
||||
: ['() => (', ...genExpression(prop.values[0], context), ')']),
|
||||
]
|
||||
}),
|
||||
)
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import { fnExpRE, isMemberExpression } from '@vue/compiler-dom'
|
||||
import {
|
||||
type SimpleExpressionNode,
|
||||
fnExpRE,
|
||||
isMemberExpression,
|
||||
} from '@vue/compiler-dom'
|
||||
import type { CodegenContext } from '../generate'
|
||||
import type { SetDynamicEventsIRNode, SetEventIRNode } from '../ir'
|
||||
import { genExpression } from './expression'
|
||||
|
@ -15,11 +19,11 @@ export function genSetEvent(
|
|||
oper: SetEventIRNode,
|
||||
context: CodegenContext,
|
||||
): CodeFragment[] {
|
||||
const { vaporHelper, options } = context
|
||||
const { vaporHelper } = context
|
||||
const { element, key, keyOverride, value, modifiers, delegate, effect } = oper
|
||||
|
||||
const name = genName()
|
||||
const handler = genEventHandler()
|
||||
const handler = genEventHandler(context, value)
|
||||
const eventOptions = genEventOptions()
|
||||
|
||||
if (delegate) {
|
||||
|
@ -51,30 +55,6 @@ export function genSetEvent(
|
|||
}
|
||||
}
|
||||
|
||||
function genEventHandler() {
|
||||
if (value && value.content.trim()) {
|
||||
const isMemberExp = isMemberExpression(value.content, options)
|
||||
const isInlineStatement = !(isMemberExp || fnExpRE.test(value.content))
|
||||
|
||||
if (isInlineStatement) {
|
||||
const expr = context.withId(() => genExpression(value, context), {
|
||||
$event: null,
|
||||
})
|
||||
const hasMultipleStatements = value.content.includes(`;`)
|
||||
return [
|
||||
'() => $event => ',
|
||||
hasMultipleStatements ? '{' : '(',
|
||||
...expr,
|
||||
hasMultipleStatements ? '}' : ')',
|
||||
]
|
||||
} else {
|
||||
return ['() => ', ...genExpression(value, context)]
|
||||
}
|
||||
}
|
||||
|
||||
return ['() => {}']
|
||||
}
|
||||
|
||||
function genEventOptions(): CodeFragment[] | undefined {
|
||||
let { options, keys, nonKeys } = modifiers
|
||||
if (!options.length && !nonKeys.length && !keys.length && !effect) return
|
||||
|
@ -111,3 +91,30 @@ export function genSetDynamicEvents(
|
|||
function genArrayExpression(elements: string[]) {
|
||||
return `[${elements.map(it => JSON.stringify(it)).join(', ')}]`
|
||||
}
|
||||
|
||||
export function genEventHandler(
|
||||
context: CodegenContext,
|
||||
value: SimpleExpressionNode | undefined,
|
||||
) {
|
||||
if (value && value.content.trim()) {
|
||||
const isMemberExp = isMemberExpression(value.content, context.options)
|
||||
const isInlineStatement = !(isMemberExp || fnExpRE.test(value.content))
|
||||
|
||||
if (isInlineStatement) {
|
||||
const expr = context.withId(() => genExpression(value, context), {
|
||||
$event: null,
|
||||
})
|
||||
const hasMultipleStatements = value.content.includes(`;`)
|
||||
return [
|
||||
'() => $event => ',
|
||||
hasMultipleStatements ? '{' : '(',
|
||||
...expr,
|
||||
hasMultipleStatements ? '}' : ')',
|
||||
]
|
||||
} else {
|
||||
return ['() => ', ...genExpression(value, context)]
|
||||
}
|
||||
}
|
||||
|
||||
return ['() => {}']
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import type {
|
|||
} from '../ir'
|
||||
import { genExpression } from './expression'
|
||||
import { type CodeFragment, NEWLINE, genCall, genMulti } from './utils'
|
||||
import { toHandlerKey } from '@vue/shared'
|
||||
|
||||
// only the static key prop will reach here
|
||||
export function genSetProp(
|
||||
|
@ -86,7 +87,7 @@ function genLiteralObjectProps(
|
|||
}
|
||||
|
||||
export function genPropKey(
|
||||
{ key: node, modifier, runtimeCamelize, runtimeHandler }: IRProp,
|
||||
{ key: node, modifier, runtimeCamelize, handler }: IRProp,
|
||||
context: CodegenContext,
|
||||
): CodeFragment[] {
|
||||
const { helper } = context
|
||||
|
@ -94,7 +95,7 @@ export function genPropKey(
|
|||
// static arg was transformed by v-bind transformer
|
||||
if (node.isStatic) {
|
||||
// only quote keys if necessary
|
||||
const keyName = node.content
|
||||
const keyName = handler ? toHandlerKey(node.content) : node.content
|
||||
return [
|
||||
[
|
||||
isSimpleIdentifier(keyName) ? keyName : JSON.stringify(keyName),
|
||||
|
@ -108,7 +109,7 @@ export function genPropKey(
|
|||
if (runtimeCamelize) {
|
||||
key = genCall(helper('camelize'), key)
|
||||
}
|
||||
if (runtimeHandler) {
|
||||
if (handler) {
|
||||
key = genCall(helper('toHandlerKey'), key)
|
||||
}
|
||||
return ['[', modifier && `${JSON.stringify(modifier)} + `, ...key, ']']
|
||||
|
|
|
@ -43,7 +43,7 @@ export interface DirectiveTransformResult {
|
|||
value: SimpleExpressionNode
|
||||
modifier?: '.' | '^'
|
||||
runtimeCamelize?: boolean
|
||||
runtimeHandler?: boolean
|
||||
handler?: boolean
|
||||
}
|
||||
|
||||
// A structural directive transform is technically also a NodeTransform;
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
import type { DirectiveTransform } from '../transform'
|
||||
import { IRNodeTypes, type KeyOverride, type SetEventIRNode } from '../ir'
|
||||
import { resolveModifiers } from '@vue/compiler-dom'
|
||||
import { extend, makeMap, toHandlerKey } from '@vue/shared'
|
||||
import { extend, makeMap } from '@vue/shared'
|
||||
import { resolveExpression } from '../utils'
|
||||
import { EMPTY_EXPRESSION } from './utils'
|
||||
|
||||
|
@ -61,14 +61,11 @@ export const transformVOn: DirectiveTransform = (dir, node, context) => {
|
|||
}
|
||||
|
||||
if (isComponent) {
|
||||
if (arg.isStatic) {
|
||||
arg = extend({}, arg, { content: toHandlerKey(arg.content) })
|
||||
}
|
||||
const handler = exp || EMPTY_EXPRESSION
|
||||
return {
|
||||
key: arg,
|
||||
value: handler,
|
||||
runtimeHandler: !arg.isStatic,
|
||||
handler: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue