From d45e47569d366b932c0e3461afc6478b45a4602d Mon Sep 17 00:00:00 2001 From: Evan You Date: Wed, 15 Apr 2020 10:35:34 -0400 Subject: [PATCH] fix(runtime-dom/v-on): support event.stopImmediatePropagation on multiple listeners close #916 --- .../runtime-dom/__tests__/patchEvents.spec.ts | 14 +++++++++++++ packages/runtime-dom/src/modules/events.ts | 20 +++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/packages/runtime-dom/__tests__/patchEvents.spec.ts b/packages/runtime-dom/__tests__/patchEvents.spec.ts index b870a8be3..2bb8e2ac0 100644 --- a/packages/runtime-dom/__tests__/patchEvents.spec.ts +++ b/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) + }) }) diff --git a/packages/runtime-dom/src/modules/events.ts b/packages/runtime-dom/src/modules/events.ts index 6789934c7..bb3ae9be0 100644 --- a/packages/runtime-dom/src/modules/events.ts +++ b/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 + } +}