Skip to content

Commit e640ec6

Browse files
Jevon617sxzz
andauthored
fix(compiler-vapor): v-on for component support $event argument (#177)
Co-authored-by: 三咲智子 Kevin Deng <[email protected]>
1 parent 9e0cd20 commit e640ec6

File tree

7 files changed

+80
-39
lines changed

7 files changed

+80
-39
lines changed

packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,17 @@ export function render(_ctx) {
9191
}"
9292
`;
9393

94+
exports[`compiler: element transform > component > should wrap as function if v-on expression is inline statement 1`] = `
95+
"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
96+
97+
export function render(_ctx) {
98+
const n0 = _createComponent(_resolveComponent("Foo"), [{
99+
onBar: () => $event => (_ctx.handleBar($event))
100+
}], true)
101+
return n0
102+
}"
103+
`;
104+
94105
exports[`compiler: element transform > component > static props 1`] = `
95106
"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
96107

packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,29 @@ describe('compiler: element transform', () => {
364364
},
365365
])
366366
})
367+
368+
test('should wrap as function if v-on expression is inline statement', () => {
369+
const { code, ir } = compileWithElementTransform(
370+
`<Foo v-on:bar="handleBar($event)" />`,
371+
)
372+
expect(code).toMatchSnapshot()
373+
expect(code).contains(`onBar: () => $event => (_ctx.handleBar($event))`)
374+
expect(ir.block.operation).toMatchObject([
375+
{
376+
type: IRNodeTypes.CREATE_COMPONENT_NODE,
377+
tag: 'Foo',
378+
props: [
379+
[
380+
{
381+
key: { content: 'bar' },
382+
handler: true,
383+
values: [{ content: 'handleBar($event)' }],
384+
},
385+
],
386+
],
387+
},
388+
])
389+
})
367390
})
368391

369392
test('static props', () => {

packages/compiler-vapor/src/generators/component.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
import { genExpression } from './expression'
1313
import { genPropKey } from './prop'
1414
import { createSimpleExpression } from '@vue/compiler-dom'
15+
import { genEventHandler } from './event'
1516

1617
// TODO: generate component slots
1718
export function genCreateComponent(
@@ -74,9 +75,10 @@ export function genCreateComponent(
7475
...props.map(prop => {
7576
return [
7677
...genPropKey(prop, context),
77-
': () => (',
78-
...genExpression(prop.values[0], context),
79-
')',
78+
': ',
79+
...(prop.handler
80+
? genEventHandler(context, prop.values[0])
81+
: ['() => (', ...genExpression(prop.values[0], context), ')']),
8082
]
8183
}),
8284
)

packages/compiler-vapor/src/generators/event.ts

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { fnExpRE, isMemberExpression } from '@vue/compiler-dom'
1+
import {
2+
type SimpleExpressionNode,
3+
fnExpRE,
4+
isMemberExpression,
5+
} from '@vue/compiler-dom'
26
import type { CodegenContext } from '../generate'
37
import type { SetDynamicEventsIRNode, SetEventIRNode } from '../ir'
48
import { genExpression } from './expression'
@@ -15,11 +19,11 @@ export function genSetEvent(
1519
oper: SetEventIRNode,
1620
context: CodegenContext,
1721
): CodeFragment[] {
18-
const { vaporHelper, options } = context
22+
const { vaporHelper } = context
1923
const { element, key, keyOverride, value, modifiers, delegate, effect } = oper
2024

2125
const name = genName()
22-
const handler = genEventHandler()
26+
const handler = genEventHandler(context, value)
2327
const eventOptions = genEventOptions()
2428

2529
if (delegate) {
@@ -51,30 +55,6 @@ export function genSetEvent(
5155
}
5256
}
5357

54-
function genEventHandler() {
55-
if (value && value.content.trim()) {
56-
const isMemberExp = isMemberExpression(value.content, options)
57-
const isInlineStatement = !(isMemberExp || fnExpRE.test(value.content))
58-
59-
if (isInlineStatement) {
60-
const expr = context.withId(() => genExpression(value, context), {
61-
$event: null,
62-
})
63-
const hasMultipleStatements = value.content.includes(`;`)
64-
return [
65-
'() => $event => ',
66-
hasMultipleStatements ? '{' : '(',
67-
...expr,
68-
hasMultipleStatements ? '}' : ')',
69-
]
70-
} else {
71-
return ['() => ', ...genExpression(value, context)]
72-
}
73-
}
74-
75-
return ['() => {}']
76-
}
77-
7858
function genEventOptions(): CodeFragment[] | undefined {
7959
let { options, keys, nonKeys } = modifiers
8060
if (!options.length && !nonKeys.length && !keys.length && !effect) return
@@ -111,3 +91,30 @@ export function genSetDynamicEvents(
11191
function genArrayExpression(elements: string[]) {
11292
return `[${elements.map(it => JSON.stringify(it)).join(', ')}]`
11393
}
94+
95+
export function genEventHandler(
96+
context: CodegenContext,
97+
value: SimpleExpressionNode | undefined,
98+
) {
99+
if (value && value.content.trim()) {
100+
const isMemberExp = isMemberExpression(value.content, context.options)
101+
const isInlineStatement = !(isMemberExp || fnExpRE.test(value.content))
102+
103+
if (isInlineStatement) {
104+
const expr = context.withId(() => genExpression(value, context), {
105+
$event: null,
106+
})
107+
const hasMultipleStatements = value.content.includes(`;`)
108+
return [
109+
'() => $event => ',
110+
hasMultipleStatements ? '{' : '(',
111+
...expr,
112+
hasMultipleStatements ? '}' : ')',
113+
]
114+
} else {
115+
return ['() => ', ...genExpression(value, context)]
116+
}
117+
}
118+
119+
return ['() => {}']
120+
}

packages/compiler-vapor/src/generators/prop.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type {
1212
} from '../ir'
1313
import { genExpression } from './expression'
1414
import { type CodeFragment, NEWLINE, genCall, genMulti } from './utils'
15+
import { toHandlerKey } from '@vue/shared'
1516

1617
// only the static key prop will reach here
1718
export function genSetProp(
@@ -86,15 +87,15 @@ function genLiteralObjectProps(
8687
}
8788

8889
export function genPropKey(
89-
{ key: node, modifier, runtimeCamelize, runtimeHandler }: IRProp,
90+
{ key: node, modifier, runtimeCamelize, handler }: IRProp,
9091
context: CodegenContext,
9192
): CodeFragment[] {
9293
const { helper } = context
9394

9495
// static arg was transformed by v-bind transformer
9596
if (node.isStatic) {
9697
// only quote keys if necessary
97-
const keyName = node.content
98+
const keyName = handler ? toHandlerKey(node.content) : node.content
9899
return [
99100
[
100101
isSimpleIdentifier(keyName) ? keyName : JSON.stringify(keyName),
@@ -108,7 +109,7 @@ export function genPropKey(
108109
if (runtimeCamelize) {
109110
key = genCall(helper('camelize'), key)
110111
}
111-
if (runtimeHandler) {
112+
if (handler) {
112113
key = genCall(helper('toHandlerKey'), key)
113114
}
114115
return ['[', modifier && `${JSON.stringify(modifier)} + `, ...key, ']']

packages/compiler-vapor/src/transform.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export interface DirectiveTransformResult {
4343
value: SimpleExpressionNode
4444
modifier?: '.' | '^'
4545
runtimeCamelize?: boolean
46-
runtimeHandler?: boolean
46+
handler?: boolean
4747
}
4848

4949
// A structural directive transform is technically also a NodeTransform;

packages/compiler-vapor/src/transforms/vOn.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
import type { DirectiveTransform } from '../transform'
77
import { IRNodeTypes, type KeyOverride, type SetEventIRNode } from '../ir'
88
import { resolveModifiers } from '@vue/compiler-dom'
9-
import { extend, makeMap, toHandlerKey } from '@vue/shared'
9+
import { extend, makeMap } from '@vue/shared'
1010
import { resolveExpression } from '../utils'
1111
import { EMPTY_EXPRESSION } from './utils'
1212

@@ -61,14 +61,11 @@ export const transformVOn: DirectiveTransform = (dir, node, context) => {
6161
}
6262

6363
if (isComponent) {
64-
if (arg.isStatic) {
65-
arg = extend({}, arg, { content: toHandlerKey(arg.content) })
66-
}
6764
const handler = exp || EMPTY_EXPRESSION
6865
return {
6966
key: arg,
7067
value: handler,
71-
runtimeHandler: !arg.isStatic,
68+
handler: true,
7269
}
7370
}
7471

0 commit comments

Comments
 (0)