Skip to content

Commit 66bacb0

Browse files
committed
make .once modifier work for component v-on as well
1 parent 6ea9a4d commit 66bacb0

File tree

4 files changed

+40
-18
lines changed

4 files changed

+40
-18
lines changed

src/core/instance/events.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ export function initEvents (vm: Component) {
77
vm._events = Object.create(null)
88
// init parent attached events
99
const listeners = vm.$options._parentListeners
10-
const on = bind(vm.$on, vm)
11-
const off = bind(vm.$off, vm)
10+
const add = (event, fn, once) => {
11+
once ? vm.$once(event, fn) : vm.$on(event, fn)
12+
}
13+
const remove = bind(vm.$off, vm)
1214
vm._updateListeners = (listeners, oldListeners) => {
13-
updateListeners(listeners, oldListeners || {}, on, off, vm)
15+
updateListeners(listeners, oldListeners || {}, add, remove, vm)
1416
}
1517
if (listeners) {
1618
vm._updateListeners(listeners)

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ export function updateListeners (
2424
capture = event.charAt(0) === '!'
2525
event = capture ? event.slice(1) : event
2626
if (Array.isArray(cur)) {
27-
add(event, (cur.invoker = arrInvoker(cur)), capture, once)
27+
add(event, (cur.invoker = arrInvoker(cur)), once, capture)
2828
} else {
2929
if (!cur.invoker) {
3030
fn = cur
3131
cur = on[name] = {}
3232
cur.fn = fn
3333
cur.invoker = fnInvoker(cur)
3434
}
35-
add(event, cur.invoker, capture, once)
35+
add(event, cur.invoker, once, capture)
3636
}
3737
} else if (cur !== old) {
3838
if (Array.isArray(old)) {
@@ -51,7 +51,7 @@ export function updateListeners (
5151
event = once ? name.slice(1) : name
5252
capture = event.charAt(0) === '!'
5353
event = capture ? event.slice(1) : event
54-
remove(event, oldOn[name].invoker, capture) // Removal of a capturing listener does not affect a non-capturing version of the same listener, and vice versa.
54+
remove(event, oldOn[name].invoker, capture)
5555
}
5656
}
5757
}

src/platforms/web/runtime/modules/events.js

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,25 @@ function updateDOMListeners (oldVnode, vnode) {
99
}
1010
const on = vnode.data.on || {}
1111
const oldOn = oldVnode.data.on || {}
12-
const add = vnode.elm._v_add || (vnode.elm._v_add = (event, handler, capture, once) => {
13-
if (once) {
14-
const oldHandler = handler
15-
handler = function (ev) {
16-
remove(event, handler, capture)
17-
18-
arguments.length === 1 ? oldHandler(ev) : oldHandler.apply(null, arguments)
12+
const add = vnode.elm._v_add || (
13+
vnode.elm._v_add = (event, handler, once, capture) => {
14+
if (once) {
15+
const oldHandler = handler
16+
handler = function (ev) {
17+
remove(event, handler, capture)
18+
arguments.length === 1
19+
? oldHandler(ev)
20+
: oldHandler.apply(null, arguments)
21+
}
1922
}
23+
vnode.elm.addEventListener(event, handler, capture)
24+
}
25+
)
26+
const remove = vnode.elm._v_remove || (
27+
vnode.elm._v_remove = (event, handler, capture) => {
28+
vnode.elm.removeEventListener(event, handler, capture)
2029
}
21-
vnode.elm.addEventListener(event, handler, capture)
22-
})
23-
const remove = vnode.elm._v_remove || (vnode.elm._v_remove = (event, handler, capture) => {
24-
vnode.elm.removeEventListener(event, handler, capture)
25-
})
30+
)
2631
updateListeners(on, oldOn, add, remove, vnode.context)
2732
}
2833

test/unit/features/directives/on.spec.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,21 @@ describe('Directive v-on', () => {
237237
expect(spy).toHaveBeenCalled()
238238
})
239239

240+
it('.once modifier should work with child components', () => {
241+
Vue.component('bar', {
242+
template: '<span>Hello</span>'
243+
})
244+
vm = new Vue({
245+
el,
246+
template: '<bar @custom.once="foo"></bar>',
247+
methods: { foo: spy }
248+
})
249+
vm.$children[0].$emit('custom')
250+
expect(spy.calls.count()).toBe(1)
251+
vm.$children[0].$emit('custom')
252+
expect(spy.calls.count()).toBe(1) // should not be called again
253+
})
254+
240255
it('remove listener', done => {
241256
const spy2 = jasmine.createSpy('remove listener')
242257
vm = new Vue({

0 commit comments

Comments
 (0)