]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-vapor): only apply v-on key modifiers to keyboard events (#14136)
authoredison <daiwei521@126.com>
Tue, 25 Nov 2025 05:49:24 +0000 (13:49 +0800)
committerGitHub <noreply@github.com>
Tue, 25 Nov 2025 05:49:24 +0000 (13:49 +0800)
packages/compiler-dom/src/index.ts
packages/compiler-dom/src/transforms/vOn.ts
packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/__snapshots__/vOn.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts
packages/compiler-vapor/src/transforms/vOn.ts

index 446a917ad7c51aad871475715bd1d910e8a06a51..5a93004c69b3059a1d029ac643e422e22832614c 100644 (file)
@@ -74,7 +74,7 @@ export {
   DOMErrorCodes,
   DOMErrorMessages,
 } from './errors'
-export { resolveModifiers } from './transforms/vOn'
+export { resolveModifiers, isKeyboardEvent } from './transforms/vOn'
 export { isValidHTMLNesting } from './htmlNesting'
 export { postTransformTransition } from './transforms/Transition'
 export * from '@vue/compiler-core'
index 723229cf34b42c6aeda6e34cc7f8c3690fa3c351..136ec842a237ce65b836cfb454b81fb03a2fc5d6 100644 (file)
@@ -28,7 +28,9 @@ const isNonKeyModifier = /*@__PURE__*/ makeMap(
 )
 // left & right could be mouse or key modifiers based on event type
 const maybeKeyModifier = /*@__PURE__*/ makeMap('left,right')
-const isKeyboardEvent = /*@__PURE__*/ makeMap(`onkeyup,onkeydown,onkeypress`)
+export const isKeyboardEvent: (key: string) => boolean = /*@__PURE__*/ makeMap(
+  `onkeyup,onkeydown,onkeypress`,
+)
 
 export const resolveModifiers = (
   key: ExpressionNode | string,
index 69ce4b9b28ac629bd15248105eb60e98634c3db4..dd2d4abb2464979fe83a47da66a48d8fa1e5140b 100644 (file)
@@ -278,11 +278,11 @@ export function render(_ctx) {
 `;
 
 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';
+"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, { onFooCaptureOnce: () => _withKeys(_withModifiers(_ctx.bar, ["stop","prevent"]), ["enter"]) }, null, true)
+  const n0 = _createComponentWithFallback(_component_Foo, { onFooCaptureOnce: () => _withModifiers(_ctx.bar, ["stop","prevent"]) }, null, true)
   return n0
 }"
 `;
@@ -434,14 +434,14 @@ export function render(_ctx) {
 `;
 
 exports[`compiler: element transform > props merging: event handlers 1`] = `
-"import { createInvoker as _createInvoker, withKeys as _withKeys, delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
-  _delegate(n0, "click", _createInvoker(_withKeys(e => _ctx.a(e), ["foo"])))
-  _delegate(n0, "click", _createInvoker(_withKeys(e => _ctx.b(e), ["bar"])))
+  _delegate(n0, "click", _createInvoker(e => _ctx.a(e)))
+  _delegate(n0, "click", _createInvoker(e => _ctx.b(e)))
   return n0
 }"
 `;
index dece57bcf3937b7cf5ab5bb0fc73bba1a073e858..ec68982edfc634e6b9421bd4259dd917963f16c8 100644 (file)
@@ -122,7 +122,7 @@ export function render(_ctx, $props, $emit, $attrs, $slots) {
   n7.$evtcontextmenu = _createInvoker(_withModifiers(_ctx.handleEvent, ["right"]))
   n8.$evtclick = _createInvoker(_withModifiers(_ctx.handleEvent, ["left"]))
   n9.$evtmouseup = _createInvoker(_withModifiers(_ctx.handleEvent, ["middle"]))
-  n10.$evtcontextmenu = _createInvoker(_withKeys(_withModifiers(_ctx.handleEvent, ["right"]), ["enter"]))
+  n10.$evtcontextmenu = _createInvoker(_withModifiers(_ctx.handleEvent, ["right"]))
   n11.$evtkeyup = _createInvoker(_withKeys(_ctx.handleEvent, ["enter"]))
   n12.$evtkeyup = _createInvoker(_withKeys(_ctx.handleEvent, ["tab"]))
   n13.$evtkeyup = _createInvoker(_withKeys(_ctx.handleEvent, ["delete"]))
index ffedee627fc7fb2e521cfc8edf17c5ba941650b6..26a8ee06baaac32d40f50fb8d1edd1cf8b2f2967 100644 (file)
@@ -963,7 +963,7 @@ describe('compiler: element transform', () => {
             key: { content: 'foo' },
             handler: true,
             handlerModifiers: {
-              keys: ['enter'],
+              keys: [],
               nonKeys: ['stop', 'prevent'],
               options: ['capture', 'once'],
             },
index fe63ece0a88851ff8b34c6daa6944fb961ce50e5..aa0662e9ca4e207818e707a95a7c9c50a7994ada 100644 (file)
@@ -2,6 +2,8 @@ import {
   ElementTypes,
   ErrorCodes,
   createCompilerError,
+  isKeyboardEvent,
+  isStaticExp,
 } from '@vue/compiler-dom'
 import type { DirectiveTransform } from '../transform'
 import { IRNodeTypes, type KeyOverride, type SetEventIRNode } from '../ir'
@@ -59,6 +61,16 @@ export const transformVOn: DirectiveTransform = (dir, node, context) => {
     }
   }
 
+  // don't gen keys guard for non-keyboard events
+  // if event name is dynamic, always wrap with keys guard
+  if (
+    keyModifiers.length &&
+    isStaticExp(arg) &&
+    !isKeyboardEvent(`on${arg.content.toLowerCase()}`)
+  ) {
+    keyModifiers.length = 0
+  }
+
   if (isComponent || isSlotOutlet) {
     const handler = exp || EMPTY_EXPRESSION
     return {