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

fix(runtime-core): improve dedupe listeners when attr fallthrough (#4912)

fix #4859
edison 4 лет назад
Родитель
Сommit
b4eb7e3866

+ 41 - 1
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() {

+ 4 - 1
packages/runtime-core/src/vnode.ts

@@ -791,7 +791,10 @@ export function mergeProps(...args: (Data & VNodeProps)[]) {
       } else if (isOn(key)) {
         const existing = ret[key]
         const incoming = toMerge[key]
-        if (existing !== incoming) {
+        if (
+          existing !== incoming &&
+          !(isArray(existing) && existing.includes(incoming))
+        ) {
           ret[key] = existing
             ? [].concat(existing as any, incoming as any)
             : incoming