Skip to content

Commit 1a1952b

Browse files
committed
handle single -> array & array -> single event handler patching (fix #4650)
1 parent 08bd81f commit 1a1952b

File tree

2 files changed

+100
-12
lines changed

2 files changed

+100
-12
lines changed

src/core/vdom/helpers/update-listeners.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ export function updateListeners (
99
remove: Function,
1010
vm: Component
1111
) {
12-
let name, cur, old, fn, event, capture, once
12+
let name, cur, old, curIsArray, oldIsArray, fn, event, capture, once
1313
for (name in on) {
1414
cur = on[name]
1515
old = oldOn[name]
16+
curIsArray = Array.isArray(cur)
17+
oldIsArray = Array.isArray(old)
1618
if (!cur) {
1719
process.env.NODE_ENV !== 'production' && warn(
1820
`Invalid handler for event "${name}": got ` + String(cur),
@@ -23,7 +25,7 @@ export function updateListeners (
2325
event = once ? name.slice(1) : name
2426
capture = event.charAt(0) === '!'
2527
event = capture ? event.slice(1) : event
26-
if (Array.isArray(cur)) {
28+
if (curIsArray) {
2729
add(event, (cur.invoker = arrInvoker(cur)), once, capture)
2830
} else {
2931
if (!cur.invoker) {
@@ -35,7 +37,9 @@ export function updateListeners (
3537
add(event, cur.invoker, once, capture)
3638
}
3739
} else if (cur !== old) {
38-
if (Array.isArray(old)) {
40+
if (curIsArray || oldIsArray) {
41+
if (!curIsArray) cur = [cur]
42+
if (!oldIsArray) old = [old]
3943
old.length = cur.length
4044
for (let i = 0; i < old.length; i++) old[i] = cur[i]
4145
on[name] = old

test/unit/modules/vdom/modules/events.spec.js

Lines changed: 93 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,125 @@ describe('vdom events module', () => {
55
it('should attach event handler to element', () => {
66
const click = jasmine.createSpy()
77
const vnode = new VNode('a', { on: { click }})
8+
89
const elm = patch(null, vnode)
910
document.body.appendChild(elm)
1011
triggerEvent(elm, 'click')
1112
expect(click.calls.count()).toBe(1)
1213
})
1314

14-
it('should not attach new listener', () => {
15+
it('should not duplicate the same listener', () => {
1516
const click = jasmine.createSpy()
1617
const vnode1 = new VNode('a', { on: { click }})
1718
const vnode2 = new VNode('a', { on: { click }})
18-
patch(null, vnode1)
19-
const elm = patch(vnode1, vnode2)
19+
20+
const elm = patch(null, vnode1)
21+
patch(vnode1, vnode2)
2022
document.body.appendChild(elm)
2123
triggerEvent(elm, 'click')
2224
expect(click.calls.count()).toBe(1)
2325
})
2426

25-
it('should attach event handlers', () => {
27+
it('should update different listener', () => {
28+
const click = jasmine.createSpy()
29+
const click2 = jasmine.createSpy()
30+
const vnode1 = new VNode('a', { on: { click }})
31+
const vnode2 = new VNode('a', { on: { click: click2 }})
32+
33+
const elm = patch(null, vnode1)
34+
document.body.appendChild(elm)
35+
triggerEvent(elm, 'click')
36+
expect(click.calls.count()).toBe(1)
37+
expect(click2.calls.count()).toBe(0)
38+
39+
patch(vnode1, vnode2)
40+
triggerEvent(elm, 'click')
41+
expect(click.calls.count()).toBe(1)
42+
expect(click2.calls.count()).toBe(1)
43+
})
44+
45+
it('should attach Array of multiple handlers', () => {
2646
const click = jasmine.createSpy()
2747
const vnode = new VNode('a', { on: { click: [click, click] }})
48+
2849
const elm = patch(null, vnode)
2950
document.body.appendChild(elm)
3051
triggerEvent(elm, 'click')
3152
expect(click.calls.count()).toBe(2)
3253
})
3354

34-
it('should change attach event handlers', () => {
55+
it('should update Array of multiple handlers', () => {
3556
const click = jasmine.createSpy()
36-
const focus = jasmine.createSpy()
37-
const vnode1 = new VNode('a', { on: { click: [click, focus] }})
57+
const click2 = jasmine.createSpy()
58+
const vnode1 = new VNode('a', { on: { click: [click, click2] }})
3859
const vnode2 = new VNode('a', { on: { click: [click] }})
39-
patch(null, vnode1)
40-
const elm = patch(vnode1, vnode2)
60+
61+
const elm = patch(null, vnode1)
62+
document.body.appendChild(elm)
63+
triggerEvent(elm, 'click')
64+
expect(click.calls.count()).toBe(1)
65+
expect(click2.calls.count()).toBe(1)
66+
67+
patch(vnode1, vnode2)
68+
triggerEvent(elm, 'click')
69+
expect(click.calls.count()).toBe(2)
70+
expect(click2.calls.count()).toBe(1)
71+
})
72+
73+
it('should remove handlers that are no longer present', () => {
74+
const click = jasmine.createSpy()
75+
const vnode1 = new VNode('a', { on: { click }})
76+
const vnode2 = new VNode('a', {})
77+
78+
const elm = patch(null, vnode1)
4179
document.body.appendChild(elm)
4280
triggerEvent(elm, 'click')
4381
expect(click.calls.count()).toBe(1)
82+
83+
patch(vnode1, vnode2)
84+
triggerEvent(elm, 'click')
85+
expect(click.calls.count()).toBe(1)
86+
})
87+
88+
it('should remove Array handlers that are no longer present', () => {
89+
const click = jasmine.createSpy()
90+
const vnode1 = new VNode('a', { on: { click: [click, click] }})
91+
const vnode2 = new VNode('a', {})
92+
93+
const elm = patch(null, vnode1)
94+
document.body.appendChild(elm)
95+
triggerEvent(elm, 'click')
96+
expect(click.calls.count()).toBe(2)
97+
98+
patch(vnode1, vnode2)
99+
triggerEvent(elm, 'click')
100+
expect(click.calls.count()).toBe(2)
101+
})
102+
103+
// #4650
104+
it('should handle single -> array or array -> single handler changes', () => {
105+
const click = jasmine.createSpy()
106+
const click2 = jasmine.createSpy()
107+
const click3 = jasmine.createSpy()
108+
const vnode1 = new VNode('a', { on: { click: [click, click2] }})
109+
const vnode2 = new VNode('a', { on: { click: click }})
110+
const vnode3 = new VNode('a', { on: { click: [click2, click3] }})
111+
112+
const elm = patch(null, vnode1)
113+
document.body.appendChild(elm)
114+
triggerEvent(elm, 'click')
115+
expect(click.calls.count()).toBe(1)
116+
expect(click2.calls.count()).toBe(1)
117+
118+
patch(vnode1, vnode2)
119+
triggerEvent(elm, 'click')
120+
expect(click.calls.count()).toBe(2)
121+
expect(click2.calls.count()).toBe(1)
122+
123+
patch(vnode2, vnode3)
124+
triggerEvent(elm, 'click')
125+
expect(click.calls.count()).toBe(2)
126+
expect(click2.calls.count()).toBe(2)
127+
expect(click3.calls.count()).toBe(1)
44128
})
45129
})

0 commit comments

Comments
 (0)