fix(v-on): refactor DOM event options modifer handling
fix #1567 Previously multiple `v-on` handlers with different event attach option modifers (`.once`, `.capture` and `.passive`) are generated as an array of objects in the form of `[{ handler, options }]` - however, this makes it pretty complex for `runtime-dom` to properly handle all possible value permutations, as each handler may need to be attached with different options. With this commit, they are now generated as event props with different keys - e.g. `v-on:click.capture` is now generated as a prop named `onClick.capture`. This allows them to be patched as separate props which makes the runtime handling much simpler.
This commit is contained in:
@@ -5,16 +5,15 @@ import {
|
||||
ElementNode,
|
||||
ObjectExpression,
|
||||
NodeTypes,
|
||||
VNodeCall
|
||||
VNodeCall,
|
||||
helperNameMap,
|
||||
CAPITALIZE
|
||||
} from '@vue/compiler-core'
|
||||
import { transformOn } from '../../src/transforms/vOn'
|
||||
import { V_ON_WITH_MODIFIERS, V_ON_WITH_KEYS } from '../../src/runtimeHelpers'
|
||||
import { transformElement } from '../../../compiler-core/src/transforms/transformElement'
|
||||
import { transformExpression } from '../../../compiler-core/src/transforms/transformExpression'
|
||||
import {
|
||||
createObjectMatcher,
|
||||
genFlagText
|
||||
} from '../../../compiler-core/__tests__/testUtils'
|
||||
import { genFlagText } from '../../../compiler-core/__tests__/testUtils'
|
||||
import { PatchFlags } from '@vue/shared'
|
||||
|
||||
function parseWithVOn(template: string, options: CompilerOptions = {}) {
|
||||
@@ -83,42 +82,37 @@ describe('compiler-dom: transform v-on', () => {
|
||||
})
|
||||
expect(prop).toMatchObject({
|
||||
type: NodeTypes.JS_PROPERTY,
|
||||
value: createObjectMatcher({
|
||||
handler: {
|
||||
callee: V_ON_WITH_MODIFIERS,
|
||||
arguments: [{ content: '_ctx.test' }, '["stop"]']
|
||||
},
|
||||
options: createObjectMatcher({
|
||||
capture: { content: 'true', isStatic: false },
|
||||
passive: { content: 'true', isStatic: false }
|
||||
})
|
||||
})
|
||||
key: {
|
||||
content: `onClick.capture.passive`
|
||||
},
|
||||
value: {
|
||||
callee: V_ON_WITH_MODIFIERS,
|
||||
arguments: [{ content: '_ctx.test' }, '["stop"]']
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('should wrap keys guard for keyboard events or dynamic events', () => {
|
||||
const {
|
||||
props: [prop]
|
||||
} = parseWithVOn(`<div @keyDown.stop.capture.ctrl.a="test"/>`, {
|
||||
} = parseWithVOn(`<div @keydown.stop.capture.ctrl.a="test"/>`, {
|
||||
prefixIdentifiers: true
|
||||
})
|
||||
expect(prop).toMatchObject({
|
||||
type: NodeTypes.JS_PROPERTY,
|
||||
value: createObjectMatcher({
|
||||
handler: {
|
||||
callee: V_ON_WITH_KEYS,
|
||||
arguments: [
|
||||
{
|
||||
callee: V_ON_WITH_MODIFIERS,
|
||||
arguments: [{ content: '_ctx.test' }, '["stop","ctrl"]']
|
||||
},
|
||||
'["a"]'
|
||||
]
|
||||
},
|
||||
options: createObjectMatcher({
|
||||
capture: { content: 'true', isStatic: false }
|
||||
})
|
||||
})
|
||||
key: {
|
||||
content: `onKeydown.capture`
|
||||
},
|
||||
value: {
|
||||
callee: V_ON_WITH_KEYS,
|
||||
arguments: [
|
||||
{
|
||||
callee: V_ON_WITH_MODIFIERS,
|
||||
arguments: [{ content: '_ctx.test' }, '["stop","ctrl"]']
|
||||
},
|
||||
'["a"]'
|
||||
]
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -206,9 +200,21 @@ describe('compiler-dom: transform v-on', () => {
|
||||
type: NodeTypes.COMPOUND_EXPRESSION,
|
||||
children: [
|
||||
`(`,
|
||||
{ children: [`"on" + (`, { content: 'event' }, `)`] },
|
||||
`).toLowerCase() === "onclick" ? "onContextmenu" : (`,
|
||||
{ children: [`"on" + (`, { content: 'event' }, `)`] },
|
||||
{
|
||||
children: [
|
||||
`"on" + _${helperNameMap[CAPITALIZE]}(`,
|
||||
{ content: 'event' },
|
||||
`)`
|
||||
]
|
||||
},
|
||||
`) === "onClick" ? "onContextmenu" : (`,
|
||||
{
|
||||
children: [
|
||||
`"on" + _${helperNameMap[CAPITALIZE]}(`,
|
||||
{ content: 'event' },
|
||||
`)`
|
||||
]
|
||||
},
|
||||
`)`
|
||||
]
|
||||
})
|
||||
@@ -232,9 +238,21 @@ describe('compiler-dom: transform v-on', () => {
|
||||
type: NodeTypes.COMPOUND_EXPRESSION,
|
||||
children: [
|
||||
`(`,
|
||||
{ children: [`"on" + (`, { content: 'event' }, `)`] },
|
||||
`).toLowerCase() === "onclick" ? "onMouseup" : (`,
|
||||
{ children: [`"on" + (`, { content: 'event' }, `)`] },
|
||||
{
|
||||
children: [
|
||||
`"on" + _${helperNameMap[CAPITALIZE]}(`,
|
||||
{ content: 'event' },
|
||||
`)`
|
||||
]
|
||||
},
|
||||
`) === "onClick" ? "onMouseup" : (`,
|
||||
{
|
||||
children: [
|
||||
`"on" + _${helperNameMap[CAPITALIZE]}(`,
|
||||
{ content: 'event' },
|
||||
`)`
|
||||
]
|
||||
},
|
||||
`)`
|
||||
]
|
||||
})
|
||||
@@ -254,24 +272,17 @@ describe('compiler-dom: transform v-on', () => {
|
||||
expect((root as any).children[0].codegenNode.patchFlag).toBe(
|
||||
genFlagText(PatchFlags.HYDRATE_EVENTS)
|
||||
)
|
||||
expect(prop.value).toMatchObject({
|
||||
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||
index: 1,
|
||||
expect(prop).toMatchObject({
|
||||
key: {
|
||||
content: `onKeyup.capture`
|
||||
},
|
||||
value: {
|
||||
type: NodeTypes.JS_OBJECT_EXPRESSION,
|
||||
properties: [
|
||||
{
|
||||
key: { content: 'handler' },
|
||||
value: {
|
||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||
callee: V_ON_WITH_KEYS
|
||||
}
|
||||
},
|
||||
{
|
||||
key: { content: 'options' },
|
||||
value: { type: NodeTypes.JS_OBJECT_EXPRESSION }
|
||||
}
|
||||
]
|
||||
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||
index: 1,
|
||||
value: {
|
||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||
callee: V_ON_WITH_KEYS
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user