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

fix(runtime-dom/v-on): support event.stopImmediatePropagation on multiple listeners

close #916
Evan You 6 лет назад
Родитель
Сommit
d45e47569d

+ 14 - 0
packages/runtime-dom/__tests__/patchEvents.spec.ts

@@ -134,4 +134,18 @@ describe(`runtime-dom: events patching`, () => {
     expect(fn).toHaveBeenCalledTimes(1)
     expect(fn2).toHaveBeenCalledWith(event)
   })
+
+  it('should support stopImmediatePropagation on multiple listeners', async () => {
+    const el = document.createElement('div')
+    const event = new Event('click')
+    const fn1 = jest.fn((e: Event) => {
+      e.stopImmediatePropagation()
+    })
+    const fn2 = jest.fn()
+    patchProp(el, 'onClick', null, [fn1, fn2])
+    el.dispatchEvent(event)
+    await timeout()
+    expect(fn1).toHaveBeenCalledTimes(1)
+    expect(fn2).toHaveBeenCalledTimes(0)
+  })
 })

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

@@ -1,4 +1,4 @@
-import { EMPTY_OBJ } from '@vue/shared'
+import { EMPTY_OBJ, isArray } from '@vue/shared'
 import {
   ComponentInternalInstance,
   callWithAsyncErrorHandling
@@ -130,7 +130,7 @@ function createInvoker(
     // AFTER it was attached.
     if (e.timeStamp >= invoker.lastUpdated - 1) {
       callWithAsyncErrorHandling(
-        invoker.value,
+        patchStopImmediatePropagation(e, invoker.value),
         instance,
         ErrorCodes.NATIVE_EVENT_HANDLER,
         [e]
@@ -142,3 +142,19 @@ function createInvoker(
   invoker.lastUpdated = getNow()
   return invoker
 }
+
+function patchStopImmediatePropagation(
+  e: Event,
+  value: EventValue
+): EventValue {
+  if (isArray(value)) {
+    const originalStop = e.stopImmediatePropagation
+    e.stopImmediatePropagation = () => {
+      originalStop.call(e)
+      ;(e as any)._stopped = true
+    }
+    return value.map(fn => (e: Event) => !(e as any)._stopped && fn(e))
+  } else {
+    return value
+  }
+}