Skip to content

Commit

Permalink
fix(runtime-dom): fix v-on same computed handler on multiple elements
Browse files Browse the repository at this point in the history
fix #1747
  • Loading branch information
yyx990803 committed Aug 3, 2020
1 parent b2a9142 commit 1c967fc
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 9 deletions.
34 changes: 34 additions & 0 deletions packages/runtime-dom/__tests__/patchEvents.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,38 @@ describe(`runtime-dom: events patching`, () => {
expect(fn1).toHaveBeenCalledTimes(1)
expect(fn2).toHaveBeenCalledTimes(0)
})

// #1747
it('should handle same computed handler function being bound on multiple targets', async () => {
const el1 = document.createElement('div')
const el2 = document.createElement('div')

const event = new Event('click')
const prevFn = jest.fn()
const nextFn = jest.fn()

patchProp(el1, 'onClick', null, prevFn)
patchProp(el2, 'onClick', null, prevFn)

el1.dispatchEvent(event)
el2.dispatchEvent(event)
await timeout()
expect(prevFn).toHaveBeenCalledTimes(2)
expect(nextFn).toHaveBeenCalledTimes(0)

patchProp(el1, 'onClick', prevFn, nextFn)
patchProp(el2, 'onClick', prevFn, nextFn)

el1.dispatchEvent(event)
el2.dispatchEvent(event)
await timeout()
expect(prevFn).toHaveBeenCalledTimes(2)
expect(nextFn).toHaveBeenCalledTimes(2)

el1.dispatchEvent(event)
el2.dispatchEvent(event)
await timeout()
expect(prevFn).toHaveBeenCalledTimes(2)
expect(nextFn).toHaveBeenCalledTimes(4)
})
})
19 changes: 10 additions & 9 deletions packages/runtime-dom/src/modules/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,25 +59,27 @@ export function removeEventListener(
}

export function patchEvent(
el: Element,
el: Element & { _vei?: Record<string, Invoker | undefined> },
rawName: string,
prevValue: EventValue | null,
nextValue: EventValue | null,
instance: ComponentInternalInstance | null = null
) {
const invoker = prevValue && prevValue.invoker
if (nextValue && invoker) {
// vei = vue event invokers
const invokers = el._vei || (el._vei = {})
const existingInvoker = invokers[rawName]
if (nextValue && existingInvoker) {
// patch
;(prevValue as EventValue).invoker = null
invoker.value = nextValue
nextValue.invoker = invoker
existingInvoker.value = nextValue
} else {
const [name, options] = parseName(rawName)
if (nextValue) {
addEventListener(el, name, createInvoker(nextValue, instance), options)
} else if (invoker) {
const invoker = (invokers[rawName] = createInvoker(nextValue, instance))
addEventListener(el, name, invoker, options)
} else if (existingInvoker) {
// remove
removeEventListener(el, name, invoker, options)
removeEventListener(el, name, existingInvoker, options)
}
}
}
Expand Down Expand Up @@ -120,7 +122,6 @@ function createInvoker(
}
}
invoker.value = initialValue
initialValue.invoker = invoker
invoker.attached = getNow()
return invoker
}
Expand Down

0 comments on commit 1c967fc

Please sign in to comment.