feat(compiler-vapor): support keys and nonKeys modifier for component event

This commit is contained in:
zhiyuanzmj 2025-03-17 17:57:51 +08:00
parent 2696f14e1c
commit efaa5b1567
6 changed files with 114 additions and 6 deletions

View File

@ -224,6 +224,36 @@ export function render(_ctx) {
}" }"
`; `;
exports[`compiler: element transform > component event with keys modifier 1`] = `
"import { resolveComponent as _resolveComponent, withKeys as _withKeys, createComponentWithFallback as _createComponentWithFallback } from 'vue';
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
const n0 = _createComponentWithFallback(_component_Foo, { onKeyup: () => _withKeys(_ctx.bar, ["enter"]) }, null, true)
return n0
}"
`;
exports[`compiler: element transform > component event with multiple modifiers and event options 1`] = `
"import { resolveComponent as _resolveComponent, withModifiers as _withModifiers, withKeys as _withKeys, createComponentWithFallback as _createComponentWithFallback } from 'vue';
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
const n0 = _createComponentWithFallback(_component_Foo, { onFooCaptureOnce: () => _withKeys(_withModifiers(_ctx.bar, ["stop","prevent"]), ["enter"]) }, null, true)
return n0
}"
`;
exports[`compiler: element transform > component event with nonKeys modifier 1`] = `
"import { resolveComponent as _resolveComponent, withModifiers as _withModifiers, createComponentWithFallback as _createComponentWithFallback } from 'vue';
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
const n0 = _createComponentWithFallback(_component_Foo, { onFoo: () => _withModifiers(_ctx.bar, ["stop","prevent"]) }, null, true)
return n0
}"
`;
exports[`compiler: element transform > component event with once modifier 1`] = ` exports[`compiler: element transform > component event with once modifier 1`] = `
"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue'; "import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';

View File

@ -878,6 +878,78 @@ describe('compiler: element transform', () => {
}) })
}) })
test('component event with keys modifier', () => {
const { code, ir } = compileWithElementTransform(
`<Foo @keyup.enter="bar" />`,
)
expect(code).toMatchSnapshot()
expect(ir.block.dynamic.children[0].operation).toMatchObject({
type: IRNodeTypes.CREATE_COMPONENT_NODE,
tag: 'Foo',
props: [
[
{
key: { content: 'keyup' },
handler: true,
handlerModifiers: {
keys: ['enter'],
nonKeys: [],
options: [],
},
},
],
],
})
})
test('component event with nonKeys modifier', () => {
const { code, ir } = compileWithElementTransform(
`<Foo @foo.stop.prevent="bar" />`,
)
expect(code).toMatchSnapshot()
expect(ir.block.dynamic.children[0].operation).toMatchObject({
type: IRNodeTypes.CREATE_COMPONENT_NODE,
tag: 'Foo',
props: [
[
{
key: { content: 'foo' },
handler: true,
handlerModifiers: {
keys: [],
nonKeys: ['stop', 'prevent'],
options: [],
},
},
],
],
})
})
test('component event with multiple modifiers and event options', () => {
const { code, ir } = compileWithElementTransform(
`<Foo @foo.enter.stop.prevent.capture.once="bar" />`,
)
expect(code).toMatchSnapshot()
expect(ir.block.dynamic.children[0].operation).toMatchObject({
type: IRNodeTypes.CREATE_COMPONENT_NODE,
tag: 'Foo',
props: [
[
{
key: { content: 'foo' },
handler: true,
handlerModifiers: {
keys: ['enter'],
nonKeys: ['stop', 'prevent'],
options: ['capture', 'once'],
},
},
],
],
})
})
test('component with dynamic event arguments', () => { test('component with dynamic event arguments', () => {
const { code, ir } = compileWithElementTransform( const { code, ir } = compileWithElementTransform(
`<Foo @[foo-bar]="bar" @[baz]="qux" />`, `<Foo @[foo-bar]="bar" @[baz]="qux" />`,

View File

@ -211,7 +211,7 @@ function genProp(prop: IRProp, context: CodegenContext, isStatic?: boolean) {
? genEventHandler( ? genEventHandler(
context, context,
prop.values[0], prop.values[0],
undefined, prop.handlerModifiers,
true /* wrap handlers passed to components */, true /* wrap handlers passed to components */,
) )
: isStatic : isStatic

View File

@ -114,9 +114,10 @@ export function genPropKey(
): CodeFragment[] { ): CodeFragment[] {
const { helper } = context const { helper } = context
const handlerModifierPostfix = handlerModifiers const handlerModifierPostfix =
? handlerModifiers.map(capitalize).join('') handlerModifiers && handlerModifiers.options
: '' ? handlerModifiers.options.map(capitalize).join('')
: ''
// static arg was transformed by v-bind transformer // static arg was transformed by v-bind transformer
if (node.isStatic) { if (node.isStatic) {
// only quote keys if necessary // only quote keys if necessary

View File

@ -23,6 +23,7 @@ import {
type IRSlots, type IRSlots,
type OperationNode, type OperationNode,
type RootIRNode, type RootIRNode,
type SetEventIRNode,
type VaporDirectiveNode, type VaporDirectiveNode,
} from './ir' } from './ir'
import { isConstantExpression, isStaticExpression } from './utils' import { isConstantExpression, isStaticExpression } from './utils'
@ -45,7 +46,7 @@ export interface DirectiveTransformResult {
modifier?: '.' | '^' modifier?: '.' | '^'
runtimeCamelize?: boolean runtimeCamelize?: boolean
handler?: boolean handler?: boolean
handlerModifiers?: string[] handlerModifiers?: SetEventIRNode['modifiers']
model?: boolean model?: boolean
modelModifiers?: string[] modelModifiers?: string[]
} }

View File

@ -65,7 +65,11 @@ export const transformVOn: DirectiveTransform = (dir, node, context) => {
key: arg, key: arg,
value: handler, value: handler,
handler: true, handler: true,
handlerModifiers: eventOptionModifiers, handlerModifiers: {
keys: keyModifiers,
nonKeys: nonKeyModifiers,
options: eventOptionModifiers,
},
} }
} }