这次我看的是vue源码里的eventsAPI部分,包括$emit/$broadcast/$dispatch等。
eventsAPI源码位置:src/instance/api/events.js
私有函数 modifyListenerCount
var hookRE = /^hook:/
function modifyListenerCount (vm, event, count) {
var parent = vm.$parent
// hooks do not get broadcasted so no need
// to do bookkeeping for them
if (!parent || !count || hookRE.test(event)) return
while (parent) {
parent._eventsCount[event] =
(parent._eventsCount[event] || 0) + count
parent = parent.$parent
}
}
在events.js里边多次调用到该函数,用于向上遍历父组件,更新事件计数器。 <li>组件的_events属性,记录着每个event绑定的回调函数(数组),比如_events[event] = [func1, func2, …]. <li>组件的_eventsCount属性,记录着自己以及子组件对每个event绑定的回调函数的总数目。每当子组件对event事件绑定了n个回调,那父组件(一直向上遍历到根)的_eventsCount[event]会+n。目前发现,_eventsCount在$broadcast会使用到。
Vue.prototype.$on
Vue.prototype.$on = function (event, fn) {
(this._events[event] || (this._events[event] = []))
.push(fn)
modifyListenerCount(this, event, 1)
return this
}
基础函数,事件监听绑定
。组件将回调函数fn保存在_events[event]中,对同一event可以绑定多个回调函数,同时,通过modifyListenerCount更新所有父组件的_eventsCount[event]。
Vue.prototype.$once
Vue.prototype.$once = function (event, fn) {
var self = this
function on () {
self.$off(event, on)
fn.apply(this, arguments)
}
on.fn = fn
this.$on(event, on)
return this
}
$once:当event事件发生时,fn只会被调用一次,调用完成后通过$off解除绑定。
Vue.prototype.$off
Vue.prototype.$off = function (event, fn) {
var cbs
// all
if (!arguments.length) {
if (this.$parent) {
for (event in this._events) {
cbs = this._events[event]
if (cbs) {
modifyListenerCount(this, event, -cbs.length)
}
}
}
this._events = {}
return this
}
// specific event
cbs = this._events[event]
if (!cbs) {
return this
}
if (arguments.length === 1) {
modifyListenerCount(this, event, -cbs.length)
this._events[event] = null
return this
}
// specific handler
var cb
var i = cbs.length
while (i--) {
cb = cbs[i]
if (cb === fn || cb.fn === fn) {
modifyListenerCount(this, event, -1)
cbs.splice(i, 1)
break
}
}
return this
}
$off:解除事件绑定,源码可以看出它的三个调用方式: