}"
`;
+exports[`compiler: element transform > component > props merging: event handlers 1`] = `
+"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
+
+export function render(_ctx) {
+ const _component_Foo = _resolveComponent("Foo")
+ const n0 = _createComponentWithFallback(_component_Foo, { onClick: () => [_ctx.a, _ctx.b] }, null, true)
+ return n0
+}"
+`;
+
+exports[`compiler: element transform > component > props merging: inline event handlers 1`] = `
+"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
+
+export function render(_ctx) {
+ const _component_Foo = _resolveComponent("Foo")
+ const _on_click = e => _ctx.a(e)
+ const _on_click1 = e => _ctx.b(e)
+ const n0 = _createComponentWithFallback(_component_Foo, { onClick: () => [_on_click, _on_click1] }, null, true)
+ return n0
+}"
+`;
+
exports[`compiler: element transform > component > resolve component from setup bindings (inline const) 1`] = `
"
const n0 = _createComponent(Example, null, null, true)
})
})
- test.todo('props merging: event handlers', () => {
- const { code, ir } = compileWithElementTransform(
+ test('props merging: event handlers', () => {
+ const { code } = compileWithElementTransform(
`<Foo @click.foo="a" @click.bar="b" />`,
)
expect(code).toMatchSnapshot()
expect(code).contains('onClick: () => [_ctx.a, _ctx.b]')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- [
- {
- key: { content: 'onClick', isStatic: true },
- values: [{ content: 'a' }, { content: 'b' }],
- },
- ],
- ],
- },
- ])
+ })
+
+ test('props merging: inline event handlers', () => {
+ const { code } = compileWithElementTransform(
+ `<Foo @click.foo="e => a(e)" @click.bar="e => b(e)" />`,
+ )
+ expect(code).toMatchSnapshot()
+ expect(code).contains('const _on_click = e => _ctx.a(e)')
+ expect(code).contains('const _on_click1 = e => _ctx.b(e)')
+ expect(code).contains('onClick: () => [_on_click, _on_click1]')
})
test.todo('props merging: style', () => {
const name = genName()
const handler = [
`${context.helper('createInvoker')}(`,
- ...genEventHandler(context, value, modifiers),
+ ...genEventHandler(context, [value], modifiers),
`)`,
]
const eventOptions = genEventOptions()
export function genEventHandler(
context: CodegenContext,
- value: SimpleExpressionNode | undefined,
+ values: (SimpleExpressionNode | undefined)[] | undefined,
modifiers: {
nonKeys: string[]
keys: string[]
// passed as component prop - need additional wrap
extraWrap: boolean = false,
): CodeFragment[] {
- let handlerExp: CodeFragment[] = [`() => {}`]
- if (value && value.content.trim()) {
- // Determine how the handler should be wrapped so it always reference the
- // latest value when invoked.
- if (isMemberExpression(value, context.options)) {
- // e.g. @click="foo.bar"
- handlerExp = genExpression(value, context)
- if (!isConstantBinding(value, context) && !extraWrap) {
- // non constant, wrap with invocation as `e => foo.bar(e)`
- // when passing as component handler, access is always dynamic so we
- // can skip this
- const isTSNode = value.ast && TS_NODE_TYPES.includes(value.ast.type)
- handlerExp = [
- `e => `,
- isTSNode ? '(' : '',
- ...handlerExp,
- isTSNode ? ')' : '',
- `(e)`,
- ]
+ let handlerExp: CodeFragment[] = []
+ if (values) {
+ values.forEach((value, index) => {
+ let exp: CodeFragment[] = []
+ if (value && value.content.trim()) {
+ // Determine how the handler should be wrapped so it always reference the
+ // latest value when invoked.
+ if (isMemberExpression(value, context.options)) {
+ // e.g. @click="foo.bar"
+ exp = genExpression(value, context)
+ if (!isConstantBinding(value, context) && !extraWrap) {
+ // non constant, wrap with invocation as `e => foo.bar(e)`
+ // when passing as component handler, access is always dynamic so we
+ // can skip this
+ const isTSNode = value.ast && TS_NODE_TYPES.includes(value.ast.type)
+ exp = [
+ `e => `,
+ isTSNode ? '(' : '',
+ ...exp,
+ isTSNode ? ')' : '',
+ `(e)`,
+ ]
+ }
+ } else if (isFnExpression(value, context.options)) {
+ // Fn expression: @click="e => foo(e)"
+ // no need to wrap in this case
+ exp = genExpression(value, context)
+ } else {
+ // inline statement
+ // @click="foo($event)" ---> $event => foo($event)
+ const referencesEvent = value.content.includes('$event')
+ const hasMultipleStatements = value.content.includes(`;`)
+ const expr = referencesEvent
+ ? context.withId(() => genExpression(value, context), {
+ $event: null,
+ })
+ : genExpression(value, context)
+ exp = [
+ referencesEvent ? '$event => ' : '() => ',
+ hasMultipleStatements ? '{' : '(',
+ ...expr,
+ hasMultipleStatements ? '}' : ')',
+ ]
+ }
+ handlerExp = handlerExp.concat([index !== 0 ? ', ' : '', ...exp])
}
- } else if (isFnExpression(value, context.options)) {
- // Fn expression: @click="e => foo(e)"
- // no need to wrap in this case
- handlerExp = genExpression(value, context)
- } else {
- // inline statement
- // @click="foo($event)" ---> $event => foo($event)
- const referencesEvent = value.content.includes('$event')
- const hasMultipleStatements = value.content.includes(`;`)
- const expr = referencesEvent
- ? context.withId(() => genExpression(value, context), {
- $event: null,
- })
- : genExpression(value, context)
- handlerExp = [
- referencesEvent ? '$event => ' : '() => ',
- hasMultipleStatements ? '{' : '(',
- ...expr,
- hasMultipleStatements ? '}' : ')',
- ]
+ })
+
+ if (values.length > 1) {
+ handlerExp = ['[', ...handlerExp, ']']
}
}
+ if (handlerExp.length === 0) handlerExp = ['() => {}']
const { keys, nonKeys } = modifiers
if (nonKeys.length)
handlerExp = genWithModifiers(context, handlerExp, nonKeys)
export function on(
el: Element,
event: string,
- handler: (e: Event) => any,
+ handler: (e: Event) => any | ((e: Event) => any)[],
options: AddEventListenerOptions & { effect?: boolean } = {},
): void {
- addEventListener(el, event, handler, options)
- if (options.effect) {
- onEffectCleanup(() => {
- el.removeEventListener(event, handler, options)
- })
+ if (isArray(handler)) {
+ handler.forEach(fn => on(el, event, fn, options))
+ } else {
+ addEventListener(el, event, handler, options)
+ if (options.effect) {
+ onEffectCleanup(() => {
+ el.removeEventListener(event, handler, options)
+ })
+ }
}
}