Răsfoiți Sursa

fix(runtime-core): fix component .once listener logic

Evan You 5 ani în urmă
părinte
comite
4bbb2b2ee6

+ 24 - 0
packages/runtime-core/__tests__/componentEmits.spec.ts

@@ -196,6 +196,30 @@ describe('component: emit', () => {
     expect(fn).toHaveBeenCalledTimes(1)
   })
 
+  test('.once with normal listener of the same name', () => {
+    const Foo = defineComponent({
+      render() {},
+      emits: {
+        foo: null
+      },
+      created() {
+        this.$emit('foo')
+        this.$emit('foo')
+      }
+    })
+    const onFoo = jest.fn()
+    const onFooOnce = jest.fn()
+    render(
+      h(Foo, {
+        onFoo,
+        onFooOnce
+      }),
+      nodeOps.createElement('div')
+    )
+    expect(onFoo).toHaveBeenCalledTimes(2)
+    expect(onFooOnce).toHaveBeenCalledTimes(1)
+  })
+
   test('isEmitListener', () => {
     const options = { click: null }
     expect(isEmitListener(options, 'onClick')).toBe(true)

+ 13 - 5
packages/runtime-core/src/componentEmits.ts

@@ -105,17 +105,25 @@ export function emit(
     handlerName = toHandlerKey(hyphenate(event))
     handler = props[handlerName]
   }
-  if (!handler) {
-    handler = props[handlerName + `Once`]
+
+  if (handler) {
+    callWithAsyncErrorHandling(
+      handler,
+      instance,
+      ErrorCodes.COMPONENT_EVENT_HANDLER,
+      args
+    )
+  }
+
+  const onceHandler = props[handlerName + `Once`]
+  if (onceHandler) {
     if (!instance.emitted) {
       ;(instance.emitted = {} as Record<string, boolean>)[handlerName] = true
     } else if (instance.emitted[handlerName]) {
       return
     }
-  }
-  if (handler) {
     callWithAsyncErrorHandling(
-      handler,
+      onceHandler,
       instance,
       ErrorCodes.COMPONENT_EVENT_HANDLER,
       args