Skip to content

Commit c660917

Browse files
committed
improve event update algorithm (thanks to suggestions from @defcc)
1 parent fe6a26b commit c660917

File tree

2 files changed

+56
-52
lines changed

2 files changed

+56
-52
lines changed
Lines changed: 47 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,75 @@
11
/* @flow */
22

3+
import { cached } from 'shared/util'
34
import { warn } from 'core/util/index'
45

6+
const normalizeEvent = cached((name: string): {
7+
name: string,
8+
once: boolean,
9+
capture: boolean
10+
} => {
11+
const once = name.charAt(0) === '~' // Prefixed last, checked first
12+
name = once ? name.slice(1) : name
13+
const capture = name.charAt(0) === '!'
14+
name = capture ? name.slice(1) : name
15+
return {
16+
name,
17+
once,
18+
capture
19+
}
20+
})
21+
22+
function createEventHandle (fn: Function | Array<Function>): {
23+
fn: Function | Array<Function>;
24+
invoker: Function;
25+
} {
26+
const handle = {
27+
fn,
28+
invoker: function () {
29+
const fn = handle.fn
30+
if (Array.isArray(fn)) {
31+
for (let i = 0; i < fn.length; i++) {
32+
fn[i].apply(null, arguments)
33+
}
34+
} else {
35+
fn.apply(null, arguments)
36+
}
37+
}
38+
}
39+
return handle
40+
}
41+
542
export function updateListeners (
643
on: Object,
744
oldOn: Object,
845
add: Function,
946
remove: Function,
1047
vm: Component
1148
) {
12-
let name, cur, old, curIsArray, oldIsArray, fn, event, capture, once
49+
let name, cur, old, event
1350
for (name in on) {
1451
cur = on[name]
1552
old = oldOn[name]
16-
curIsArray = Array.isArray(cur)
17-
oldIsArray = Array.isArray(old)
53+
event = normalizeEvent(name)
1854
if (!cur) {
1955
process.env.NODE_ENV !== 'production' && warn(
20-
`Invalid handler for event "${name}": got ` + String(cur),
56+
`Invalid handler for event "${event.name}": got ` + String(cur),
2157
vm
2258
)
2359
} else if (!old) {
24-
once = name.charAt(0) === '~' // Prefixed last, checked first
25-
event = once ? name.slice(1) : name
26-
capture = event.charAt(0) === '!'
27-
event = capture ? event.slice(1) : event
28-
if (curIsArray) {
29-
add(event, (cur.invoker = arrInvoker(cur)), once, capture)
30-
} else {
31-
if (!cur.invoker) {
32-
fn = cur
33-
cur = on[name] = {}
34-
cur.fn = fn
35-
cur.invoker = fnInvoker(cur)
36-
}
37-
add(event, cur.invoker, once, capture)
60+
if (!cur.invoker) {
61+
cur = on[name] = createEventHandle(cur)
3862
}
63+
add(event.name, cur.invoker, event.once, event.capture)
3964
} else if (cur !== old) {
40-
if (curIsArray || oldIsArray) {
41-
if (!curIsArray) cur = [cur]
42-
if (!oldIsArray) old = [old]
43-
old.length = cur.length
44-
for (let i = 0; i < old.length; i++) old[i] = cur[i]
45-
on[name] = old
46-
} else {
47-
old.fn = cur
48-
on[name] = old
49-
}
65+
old.fn = cur
66+
on[name] = old
5067
}
5168
}
5269
for (name in oldOn) {
5370
if (!on[name]) {
54-
once = name.charAt(0) === '~' // Prefixed last, checked first
55-
event = once ? name.slice(1) : name
56-
capture = event.charAt(0) === '!'
57-
event = capture ? event.slice(1) : event
58-
remove(event, oldOn[name].invoker, capture)
59-
}
60-
}
61-
}
62-
63-
function arrInvoker (arr: Array<Function>): Function {
64-
return function (ev) {
65-
const single = arguments.length === 1
66-
for (let i = 0; i < arr.length; i++) {
67-
single ? arr[i](ev) : arr[i].apply(null, arguments)
71+
event = normalizeEvent(name)
72+
remove(event.name, oldOn[name].invoker, event.capture)
6873
}
6974
}
7075
}
71-
72-
function fnInvoker (o: { fn: Function }): Function {
73-
return function (ev) {
74-
const single = arguments.length === 1
75-
single ? o.fn(ev) : o.fn.apply(null, arguments)
76-
}
77-
}

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,24 +105,30 @@ describe('vdom events module', () => {
105105
const click = jasmine.createSpy()
106106
const click2 = jasmine.createSpy()
107107
const click3 = jasmine.createSpy()
108+
const vnode0 = new VNode('a', { on: { click: click }})
108109
const vnode1 = new VNode('a', { on: { click: [click, click2] }})
109110
const vnode2 = new VNode('a', { on: { click: click }})
110111
const vnode3 = new VNode('a', { on: { click: [click2, click3] }})
111112

112-
const elm = patch(null, vnode1)
113+
const elm = patch(null, vnode0)
113114
document.body.appendChild(elm)
114115
triggerEvent(elm, 'click')
115116
expect(click.calls.count()).toBe(1)
117+
expect(click2.calls.count()).toBe(0)
118+
119+
patch(vnode0, vnode1)
120+
triggerEvent(elm, 'click')
121+
expect(click.calls.count()).toBe(2)
116122
expect(click2.calls.count()).toBe(1)
117123

118124
patch(vnode1, vnode2)
119125
triggerEvent(elm, 'click')
120-
expect(click.calls.count()).toBe(2)
126+
expect(click.calls.count()).toBe(3)
121127
expect(click2.calls.count()).toBe(1)
122128

123129
patch(vnode2, vnode3)
124130
triggerEvent(elm, 'click')
125-
expect(click.calls.count()).toBe(2)
131+
expect(click.calls.count()).toBe(3)
126132
expect(click2.calls.count()).toBe(2)
127133
expect(click3.calls.count()).toBe(1)
128134
})

0 commit comments

Comments
 (0)