Skip to content

Commit ee6ad6a

Browse files
committed
fix v-on .once on multiple elements (fix #4655)
1 parent 1a1952b commit ee6ad6a

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,17 @@ import { updateListeners } from 'core/vdom/helpers/index'
44

55
let target: HTMLElement
66

7-
function add (event: string, handler: Function, once: boolean, capture: boolean) {
7+
function add (
8+
event: string,
9+
handler: Function,
10+
once: boolean,
11+
capture: boolean
12+
) {
813
if (once) {
914
const oldHandler = handler
15+
const _target = target // save current target element in closure
1016
handler = function (ev) {
11-
remove(event, handler, capture)
17+
remove(event, handler, capture, _target)
1218
arguments.length === 1
1319
? oldHandler(ev)
1420
: oldHandler.apply(null, arguments)
@@ -17,8 +23,13 @@ function add (event: string, handler: Function, once: boolean, capture: boolean)
1723
target.addEventListener(event, handler, capture)
1824
}
1925

20-
function remove (event: string, handler: Function, capture: boolean) {
21-
target.removeEventListener(event, handler, capture)
26+
function remove (
27+
event: string,
28+
handler: Function,
29+
capture: boolean,
30+
_target?: HTMLElement
31+
) {
32+
(_target || target).removeEventListener(event, handler, capture)
2233
}
2334

2435
function updateDOMListeners (oldVnode: VNodeWithData, vnode: VNodeWithData) {

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,29 @@ describe('Directive v-on', () => {
130130
expect(spy.calls.count()).toBe(1) // should no longer trigger
131131
})
132132

133+
// #4655
134+
it('should handle .once on multiple elements properly', () => {
135+
vm = new Vue({
136+
el,
137+
template: `
138+
<div>
139+
<button ref="one" @click.once="foo">one</button>
140+
<button ref="two" @click.once="foo">two</button>
141+
</div>
142+
`,
143+
methods: { foo: spy }
144+
})
145+
triggerEvent(vm.$refs.one, 'click')
146+
expect(spy.calls.count()).toBe(1)
147+
triggerEvent(vm.$refs.one, 'click')
148+
expect(spy.calls.count()).toBe(1)
149+
triggerEvent(vm.$refs.two, 'click')
150+
expect(spy.calls.count()).toBe(2)
151+
triggerEvent(vm.$refs.one, 'click')
152+
triggerEvent(vm.$refs.two, 'click')
153+
expect(spy.calls.count()).toBe(2)
154+
})
155+
133156
it('should support capture and once', () => {
134157
const callOrder = []
135158
vm = new Vue({

0 commit comments

Comments
 (0)