Просмотр исходного кода

default event propagation to false

Evan You 10 лет назад
Родитель
Сommit
cc7377d4b8
4 измененных файлов с 57 добавлено и 19 удалено
  1. 13 16
      src/api/events.js
  2. 9 0
      src/deprecations.js
  3. 1 1
      src/instance/init.js
  4. 34 2
      test/unit/specs/api/events_spec.js

+ 13 - 16
src/api/events.js

@@ -87,23 +87,20 @@ exports.$off = function (event, fn) {
  */
 
 exports.$emit = function (event) {
-  this._eventCancelled = false
+  this._shouldPropagate = false
   var cbs = this._events[event]
   if (cbs) {
-    // avoid leaking arguments:
-    // http://jsperf.com/closure-with-arguments
-    var i = arguments.length - 1
-    var args = new Array(i)
-    while (i--) {
-      args[i] = arguments[i + 1]
-    }
-    i = 0
     cbs = cbs.length > 1
       ? _.toArray(cbs)
       : cbs
-    for (var l = cbs.length; i < l; i++) {
-      if (cbs[i].apply(this, args) === false) {
-        this._eventCancelled = true
+    var args = _.toArray(arguments, 1)
+    for (var i = 0, l = cbs.length; i < l; i++) {
+      var res = cbs[i].apply(this, args)
+      if (res === true) {
+        this._shouldPropagate = true
+      }
+      if (process.env.NODE_ENV !== 'production' && res === false) {
+        _.deprecation.PROPAGATION(event)
       }
     }
   }
@@ -125,7 +122,7 @@ exports.$broadcast = function (event) {
   for (var i = 0, l = children.length; i < l; i++) {
     var child = children[i]
     child.$emit.apply(child, arguments)
-    if (!child._eventCancelled) {
+    if (child._shouldPropagate) {
       child.$broadcast.apply(child, arguments)
     }
   }
@@ -143,9 +140,9 @@ exports.$dispatch = function () {
   var parent = this.$parent
   while (parent) {
     parent.$emit.apply(parent, arguments)
-    parent = parent._eventCancelled
-      ? null
-      : parent.$parent
+    parent = parent._shouldPropagate
+      ? parent.$parent
+      : null
   }
   return this
 }

+ 9 - 0
src/deprecations.js

@@ -177,6 +177,15 @@ if (process.env.NODE_ENV !== 'production') {
         'The "key" filter will be deprecated in 1.0.0. Use the new ' +
         'on-keyup:key="handler" syntax instead.'
       )
+    },
+
+    PROPAGATION: function (event) {
+      warn(
+        'No need to return false in handler for event "' + event + '": events ' +
+        'no longer propagate beyond the first triggered handler unless the ' +
+        'handler explicitly returns true. See https://github.com/yyx990803/vue/issues/1175 ' +
+        'for more details.'
+      )
     }
 
   }

+ 1 - 1
src/instance/init.js

@@ -31,7 +31,7 @@ exports._init = function (options) {
   // events bookkeeping
   this._events = {}            // registered callbacks
   this._eventsCount = {}       // for $broadcast optimization
-  this._eventCancelled = false // for event cancellation
+  this._shouldPropagate = false // for event propagation
 
   // fragment instance properties
   this._isFragment = false

+ 34 - 2
test/unit/specs/api/events_spec.js

@@ -66,6 +66,20 @@ describe('Events API', function () {
     child2.$on('test', spy)
     child3.$on('test', spy)
     vm.$broadcast('test')
+    expect(spy.calls.count()).toBe(2) // should not propagate by default
+  })
+
+  it('$broadcast with propagation', function () {
+    var child1 = vm.$addChild()
+    var child2 = vm.$addChild()
+    var child3 = child1.$addChild()
+    child1.$on('test', function () {
+      spy()
+      return true
+    })
+    child2.$on('test', spy)
+    child3.$on('test', spy)
+    vm.$broadcast('test')
     expect(spy.calls.count()).toBe(3)
   })
 
@@ -75,7 +89,13 @@ describe('Events API', function () {
     // hooks should not incurr the bookkeeping cost
     child.$on('hook:created', function () {})
     expect(vm._eventsCount['hook:created']).toBeUndefined()
-    child.$on('test', spy)
+
+    function handler () {
+      spy()
+      return true
+    }
+
+    child.$on('test', handler)
     expect(vm._eventsCount['test']).toBe(1)
     // child2's $emit & $broadcast
     // shouldn't get called if no child listens to the event
@@ -84,7 +104,7 @@ describe('Events API', function () {
     vm.$broadcast('test')
     expect(spy.calls.count()).toBe(1)
     // check $off bookkeeping
-    child.$off('test', spy)
+    child.$off('test', handler)
     expect(vm._eventsCount['test']).toBe(0)
     function noop () {}
     child.$on('test', noop)
@@ -117,6 +137,18 @@ describe('Events API', function () {
     child.$on('test', spy)
     vm.$on('test', spy)
     child2.$dispatch('test')
+    expect(spy.calls.count()).toBe(1) // should not propagate by default
+  })
+
+  it('$dispatch with propagation', function () {
+    var child = vm.$addChild()
+    var child2 = child.$addChild()
+    child.$on('test', function () {
+      spy()
+      return true
+    })
+    vm.$on('test', spy)
+    child2.$dispatch('test')
     expect(spy.calls.count()).toBe(2)
   })