From 74bd85218dfb7853873ab04f5d85029a47d5507e Mon Sep 17 00:00:00 2001 From: daiwei Date: Sun, 7 Nov 2021 14:06:58 +0800 Subject: [PATCH 1/2] fix(runtime-core): improve dedupe listeners when attr fallthrough --- .../rendererAttrsFallthrough.spec.ts | 42 ++++++++++++++++++- packages/runtime-core/src/vnode.ts | 2 + 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts b/packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts index d358431d66b..f23cdf6a27c 100644 --- a/packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts +++ b/packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts @@ -11,7 +11,8 @@ import { createBlock, FunctionalComponent, createCommentVNode, - Fragment + Fragment, + withModifiers } from '@vue/runtime-dom' import { PatchFlags } from '@vue/shared/src' @@ -383,6 +384,45 @@ describe('attribute fallthrough', () => { expect(`Extraneous non-emits event listeners`).toHaveBeenWarned() }) + it('should dedupe same listeners when $attrs is used during render', () => { + const click = jest.fn() + const count = ref(0) + + function inc() { + count.value++ + click() + } + + const Parent = { + render() { + return h(Child, { onClick: inc }) + } + } + + const Child = defineComponent({ + render() { + return h( + 'div', + mergeProps( + { + onClick: withModifiers(() => {}, ['prevent', 'stop']) + }, + this.$attrs + ) + ) + } + }) + + const root = document.createElement('div') + document.body.appendChild(root) + render(h(Parent), root) + + const node = root.children[0] as HTMLElement + node.dispatchEvent(new CustomEvent('click')) + expect(click).toHaveBeenCalledTimes(1) + expect(count.value).toBe(1) + }) + it('should not warn when $attrs is used during render', () => { const Parent = { render() { diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index 089147a38f7..86bc722bcba 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/packages/runtime-core/src/vnode.ts @@ -792,6 +792,8 @@ export function mergeProps(...args: (Data & VNodeProps)[]) { const existing = ret[key] const incoming = toMerge[key] if (existing !== incoming) { + if (isArray(existing) && existing.indexOf(incoming) !== -1) continue + ret[key] = existing ? [].concat(existing as any, incoming as any) : incoming From 0f9d724028bcb09382177eaf0fefb93f7fa0c66a Mon Sep 17 00:00:00 2001 From: Evan You Date: Sun, 14 Nov 2021 22:14:51 -0500 Subject: [PATCH 2/2] Update vnode.ts --- packages/runtime-core/src/vnode.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index 86bc722bcba..306afbcc3d2 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/packages/runtime-core/src/vnode.ts @@ -791,9 +791,10 @@ export function mergeProps(...args: (Data & VNodeProps)[]) { } else if (isOn(key)) { const existing = ret[key] const incoming = toMerge[key] - if (existing !== incoming) { - if (isArray(existing) && existing.indexOf(incoming) !== -1) continue - + if ( + existing !== incoming && + !(isArray(existing) && existing.includes(incoming)) + ) { ret[key] = existing ? [].concat(existing as any, incoming as any) : incoming