github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/libs/vue-1.0.24/src/instance/api/events.js (about) 1 import { toArray } from '../../util/index' 2 3 export default function (Vue) { 4 /** 5 * Listen on the given `event` with `fn`. 6 * 7 * @param {String} event 8 * @param {Function} fn 9 */ 10 11 Vue.prototype.$on = function (event, fn) { 12 (this._events[event] || (this._events[event] = [])) 13 .push(fn) 14 modifyListenerCount(this, event, 1) 15 return this 16 } 17 18 /** 19 * Adds an `event` listener that will be invoked a single 20 * time then automatically removed. 21 * 22 * @param {String} event 23 * @param {Function} fn 24 */ 25 26 Vue.prototype.$once = function (event, fn) { 27 var self = this 28 function on () { 29 self.$off(event, on) 30 fn.apply(this, arguments) 31 } 32 on.fn = fn 33 this.$on(event, on) 34 return this 35 } 36 37 /** 38 * Remove the given callback for `event` or all 39 * registered callbacks. 40 * 41 * @param {String} event 42 * @param {Function} fn 43 */ 44 45 Vue.prototype.$off = function (event, fn) { 46 var cbs 47 // all 48 if (!arguments.length) { 49 if (this.$parent) { 50 for (event in this._events) { 51 cbs = this._events[event] 52 if (cbs) { 53 modifyListenerCount(this, event, -cbs.length) 54 } 55 } 56 } 57 this._events = {} 58 return this 59 } 60 // specific event 61 cbs = this._events[event] 62 if (!cbs) { 63 return this 64 } 65 if (arguments.length === 1) { 66 modifyListenerCount(this, event, -cbs.length) 67 this._events[event] = null 68 return this 69 } 70 // specific handler 71 var cb 72 var i = cbs.length 73 while (i--) { 74 cb = cbs[i] 75 if (cb === fn || cb.fn === fn) { 76 modifyListenerCount(this, event, -1) 77 cbs.splice(i, 1) 78 break 79 } 80 } 81 return this 82 } 83 84 /** 85 * Trigger an event on self. 86 * 87 * @param {String|Object} event 88 * @return {Boolean} shouldPropagate 89 */ 90 91 Vue.prototype.$emit = function (event) { 92 var isSource = typeof event === 'string' 93 event = isSource 94 ? event 95 : event.name 96 var cbs = this._events[event] 97 var shouldPropagate = isSource || !cbs 98 if (cbs) { 99 cbs = cbs.length > 1 100 ? toArray(cbs) 101 : cbs 102 // this is a somewhat hacky solution to the question raised 103 // in #2102: for an inline component listener like <comp @test="doThis">, 104 // the propagation handling is somewhat broken. Therefore we 105 // need to treat these inline callbacks differently. 106 var hasParentCbs = isSource && cbs.some(function (cb) { 107 return cb._fromParent 108 }) 109 if (hasParentCbs) { 110 shouldPropagate = false 111 } 112 var args = toArray(arguments, 1) 113 for (var i = 0, l = cbs.length; i < l; i++) { 114 var cb = cbs[i] 115 var res = cb.apply(this, args) 116 if (res === true && (!hasParentCbs || cb._fromParent)) { 117 shouldPropagate = true 118 } 119 } 120 } 121 return shouldPropagate 122 } 123 124 /** 125 * Recursively broadcast an event to all children instances. 126 * 127 * @param {String|Object} event 128 * @param {...*} additional arguments 129 */ 130 131 Vue.prototype.$broadcast = function (event) { 132 var isSource = typeof event === 'string' 133 event = isSource 134 ? event 135 : event.name 136 // if no child has registered for this event, 137 // then there's no need to broadcast. 138 if (!this._eventsCount[event]) return 139 var children = this.$children 140 var args = toArray(arguments) 141 if (isSource) { 142 // use object event to indicate non-source emit 143 // on children 144 args[0] = { name: event, source: this } 145 } 146 for (var i = 0, l = children.length; i < l; i++) { 147 var child = children[i] 148 var shouldPropagate = child.$emit.apply(child, args) 149 if (shouldPropagate) { 150 child.$broadcast.apply(child, args) 151 } 152 } 153 return this 154 } 155 156 /** 157 * Recursively propagate an event up the parent chain. 158 * 159 * @param {String} event 160 * @param {...*} additional arguments 161 */ 162 163 Vue.prototype.$dispatch = function (event) { 164 var shouldPropagate = this.$emit.apply(this, arguments) 165 if (!shouldPropagate) return 166 var parent = this.$parent 167 var args = toArray(arguments) 168 // use object event to indicate non-source emit 169 // on parents 170 args[0] = { name: event, source: this } 171 while (parent) { 172 shouldPropagate = parent.$emit.apply(parent, args) 173 parent = shouldPropagate 174 ? parent.$parent 175 : null 176 } 177 return this 178 } 179 180 /** 181 * Modify the listener counts on all parents. 182 * This bookkeeping allows $broadcast to return early when 183 * no child has listened to a certain event. 184 * 185 * @param {Vue} vm 186 * @param {String} event 187 * @param {Number} count 188 */ 189 190 var hookRE = /^hook:/ 191 function modifyListenerCount (vm, event, count) { 192 var parent = vm.$parent 193 // hooks do not get broadcasted so no need 194 // to do bookkeeping for them 195 if (!parent || !count || hookRE.test(event)) return 196 while (parent) { 197 parent._eventsCount[event] = 198 (parent._eventsCount[event] || 0) + count 199 parent = parent.$parent 200 } 201 } 202 }