Bläddra i källkod

fix v-on .once on multiple elements (fix #4655)

Evan You 9 år sedan
förälder
incheckning
ee6ad6af0e
2 ändrade filer med 38 tillägg och 4 borttagningar
  1. 15 4
      src/platforms/web/runtime/modules/events.js
  2. 23 0
      test/unit/features/directives/on.spec.js

+ 15 - 4
src/platforms/web/runtime/modules/events.js

@@ -4,11 +4,17 @@ import { updateListeners } from 'core/vdom/helpers/index'
 
 let target: HTMLElement
 
-function add (event: string, handler: Function, once: boolean, capture: boolean) {
+function add (
+  event: string,
+  handler: Function,
+  once: boolean,
+  capture: boolean
+) {
   if (once) {
     const oldHandler = handler
+    const _target = target // save current target element in closure
     handler = function (ev) {
-      remove(event, handler, capture)
+      remove(event, handler, capture, _target)
       arguments.length === 1
         ? oldHandler(ev)
         : oldHandler.apply(null, arguments)
@@ -17,8 +23,13 @@ function add (event: string, handler: Function, once: boolean, capture: boolean)
   target.addEventListener(event, handler, capture)
 }
 
-function remove (event: string, handler: Function, capture: boolean) {
-  target.removeEventListener(event, handler, capture)
+function remove (
+  event: string,
+  handler: Function,
+  capture: boolean,
+  _target?: HTMLElement
+) {
+  (_target || target).removeEventListener(event, handler, capture)
 }
 
 function updateDOMListeners (oldVnode: VNodeWithData, vnode: VNodeWithData) {

+ 23 - 0
test/unit/features/directives/on.spec.js

@@ -130,6 +130,29 @@ describe('Directive v-on', () => {
     expect(spy.calls.count()).toBe(1) // should no longer trigger
   })
 
+  // #4655
+  it('should handle .once on multiple elements properly', () => {
+    vm = new Vue({
+      el,
+      template: `
+        <div>
+          <button ref="one" @click.once="foo">one</button>
+          <button ref="two" @click.once="foo">two</button>
+        </div>
+      `,
+      methods: { foo: spy }
+    })
+    triggerEvent(vm.$refs.one, 'click')
+    expect(spy.calls.count()).toBe(1)
+    triggerEvent(vm.$refs.one, 'click')
+    expect(spy.calls.count()).toBe(1)
+    triggerEvent(vm.$refs.two, 'click')
+    expect(spy.calls.count()).toBe(2)
+    triggerEvent(vm.$refs.one, 'click')
+    triggerEvent(vm.$refs.two, 'click')
+    expect(spy.calls.count()).toBe(2)
+  })
+
   it('should support capture and once', () => {
     const callOrder = []
     vm = new Vue({