Ver código fonte

make .once modifier work for component v-on as well

Evan You 9 anos atrás
pai
commit
66bacb015c

+ 5 - 3
src/core/instance/events.js

@@ -7,10 +7,12 @@ export function initEvents (vm: Component) {
   vm._events = Object.create(null)
   vm._events = Object.create(null)
   // init parent attached events
   // init parent attached events
   const listeners = vm.$options._parentListeners
   const listeners = vm.$options._parentListeners
-  const on = bind(vm.$on, vm)
-  const off = bind(vm.$off, vm)
+  const add = (event, fn, once) => {
+    once ? vm.$once(event, fn) : vm.$on(event, fn)
+  }
+  const remove = bind(vm.$off, vm)
   vm._updateListeners = (listeners, oldListeners) => {
   vm._updateListeners = (listeners, oldListeners) => {
-    updateListeners(listeners, oldListeners || {}, on, off, vm)
+    updateListeners(listeners, oldListeners || {}, add, remove, vm)
   }
   }
   if (listeners) {
   if (listeners) {
     vm._updateListeners(listeners)
     vm._updateListeners(listeners)

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

@@ -24,7 +24,7 @@ export function updateListeners (
       capture = event.charAt(0) === '!'
       capture = event.charAt(0) === '!'
       event = capture ? event.slice(1) : event
       event = capture ? event.slice(1) : event
       if (Array.isArray(cur)) {
       if (Array.isArray(cur)) {
-        add(event, (cur.invoker = arrInvoker(cur)), capture, once)
+        add(event, (cur.invoker = arrInvoker(cur)), once, capture)
       } else {
       } else {
         if (!cur.invoker) {
         if (!cur.invoker) {
           fn = cur
           fn = cur
@@ -32,7 +32,7 @@ export function updateListeners (
           cur.fn = fn
           cur.fn = fn
           cur.invoker = fnInvoker(cur)
           cur.invoker = fnInvoker(cur)
         }
         }
-        add(event, cur.invoker, capture, once)
+        add(event, cur.invoker, once, capture)
       }
       }
     } else if (cur !== old) {
     } else if (cur !== old) {
       if (Array.isArray(old)) {
       if (Array.isArray(old)) {
@@ -51,7 +51,7 @@ export function updateListeners (
       event = once ? name.slice(1) : name
       event = once ? name.slice(1) : name
       capture = event.charAt(0) === '!'
       capture = event.charAt(0) === '!'
       event = capture ? event.slice(1) : event
       event = capture ? event.slice(1) : event
-      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.
+      remove(event, oldOn[name].invoker, capture)
     }
     }
   }
   }
 }
 }

+ 17 - 12
src/platforms/web/runtime/modules/events.js

@@ -9,20 +9,25 @@ function updateDOMListeners (oldVnode, vnode) {
   }
   }
   const on = vnode.data.on || {}
   const on = vnode.data.on || {}
   const oldOn = oldVnode.data.on || {}
   const oldOn = oldVnode.data.on || {}
-  const add = vnode.elm._v_add || (vnode.elm._v_add = (event, handler, capture, once) => {
-    if (once) {
-      const oldHandler = handler
-      handler = function (ev) {
-        remove(event, handler, capture)
-
-        arguments.length === 1 ? oldHandler(ev) : oldHandler.apply(null, arguments)
+  const add = vnode.elm._v_add || (
+    vnode.elm._v_add = (event, handler, once, capture) => {
+      if (once) {
+        const oldHandler = handler
+        handler = function (ev) {
+          remove(event, handler, capture)
+          arguments.length === 1
+            ? oldHandler(ev)
+            : oldHandler.apply(null, arguments)
+        }
       }
       }
+      vnode.elm.addEventListener(event, handler, capture)
+    }
+  )
+  const remove = vnode.elm._v_remove || (
+    vnode.elm._v_remove = (event, handler, capture) => {
+      vnode.elm.removeEventListener(event, handler, capture)
     }
     }
-    vnode.elm.addEventListener(event, handler, capture)
-  })
-  const remove = vnode.elm._v_remove || (vnode.elm._v_remove = (event, handler, capture) => {
-    vnode.elm.removeEventListener(event, handler, capture)
-  })
+  )
   updateListeners(on, oldOn, add, remove, vnode.context)
   updateListeners(on, oldOn, add, remove, vnode.context)
 }
 }
 
 

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

@@ -237,6 +237,21 @@ describe('Directive v-on', () => {
     expect(spy).toHaveBeenCalled()
     expect(spy).toHaveBeenCalled()
   })
   })
 
 
+  it('.once modifier should work with child components', () => {
+    Vue.component('bar', {
+      template: '<span>Hello</span>'
+    })
+    vm = new Vue({
+      el,
+      template: '<bar @custom.once="foo"></bar>',
+      methods: { foo: spy }
+    })
+    vm.$children[0].$emit('custom')
+    expect(spy.calls.count()).toBe(1)
+    vm.$children[0].$emit('custom')
+    expect(spy.calls.count()).toBe(1) // should not be called again
+  })
+
   it('remove listener', done => {
   it('remove listener', done => {
     const spy2 = jasmine.createSpy('remove listener')
     const spy2 = jasmine.createSpy('remove listener')
     vm = new Vue({
     vm = new Vue({