Просмотр исходного кода

fix(runtime-vapor): parse dynamic v-bind event options like vdom

daiwei 2 дней назад
Родитель
Сommit
5100a6ec7e

+ 4 - 0
packages/runtime-dom/src/index.ts

@@ -333,6 +333,10 @@ export { ensureRenderer, ensureHydrationRenderer, normalizeContainer }
  * @internal
  */
 export { patchStyle } from './modules/style'
+/**
+ * @internal
+ */
+export { parseEventName } from './modules/events'
 /**
  * @internal
  */

+ 4 - 2
packages/runtime-dom/src/modules/events.ts

@@ -49,7 +49,7 @@ export function patchEvent(
       ? sanitizeEventValue(nextValue, rawName)
       : (nextValue as EventValue)
   } else {
-    const [name, options] = parseName(rawName)
+    const [name, options] = parseEventName(rawName)
     if (nextValue) {
       // add
       const invoker = (invokers[rawName] = createInvoker(
@@ -69,7 +69,9 @@ export function patchEvent(
 
 const optionsModifierRE = /(?:Once|Passive|Capture)$/
 
-function parseName(name: string): [string, EventListenerOptions | undefined] {
+export function parseEventName(
+  name: string,
+): [string, EventListenerOptions | undefined] {
   let options: EventListenerOptions | undefined
   if (optionsModifierRE.test(name)) {
     options = {}

+ 34 - 0
packages/runtime-vapor/__tests__/dom/prop.spec.ts

@@ -694,6 +694,40 @@ describe('patchProp', () => {
       expect(handler).toHaveBeenCalledTimes(2)
     })
 
+    test('should parse dynamic event option modifiers like vdom', () => {
+      const el = document.createElement('button')
+      const handler = vi.fn()
+      const scope = effectScope()
+      scope.run(() => {
+        renderEffect(() => {
+          setDynamicProps(el, [{ onClickOnceCapture: handler }])
+        })
+      })
+
+      el.dispatchEvent(new Event('click'))
+      el.dispatchEvent(new Event('click'))
+
+      expect(handler).toHaveBeenCalledTimes(1)
+      scope.stop()
+    })
+
+    test('should parse dynamic event names like vdom', () => {
+      const el = document.createElement('button')
+      const handler = vi.fn()
+      const scope = effectScope()
+      scope.run(() => {
+        renderEffect(() => {
+          setDynamicProps(el, [{ onMyEventOnce: handler }])
+        })
+      })
+
+      el.dispatchEvent(new Event('my-event'))
+      el.dispatchEvent(new Event('my-event'))
+
+      expect(handler).toHaveBeenCalledTimes(1)
+      scope.stop()
+    })
+
     test('should restore fallthrough state when dynamic props throw', () => {
       const el = document.createElement('div')
       const attrs: Record<string, any> = {}

+ 3 - 1
packages/runtime-vapor/src/dom/prop.ts

@@ -26,6 +26,7 @@ import {
   isValidHtmlOrSvgAttribute,
   logMismatchError,
   mergeProps,
+  parseEventName,
   patchStyle,
   queuePostFlushCb,
   shouldSetAsProp,
@@ -586,7 +587,8 @@ export function setDynamicProp(
     if (shouldSkipFallthroughKey(el, key)) {
       return
     }
-    onBinding(el, key[2].toLowerCase() + key.slice(3), value)
+    const [event, options] = parseEventName(key)
+    onBinding(el, event, value, options)
   } else if (
     // force hydrate v-bind with .prop modifiers
     (forceHydrate = key[0] === '.')