$emit
與$on
vue 事件相關的函數掛載在vue的原型對象上面。分別爲:vue
$on
vm.$on(event, callback)
數組
const hookRE = /^hook:/
Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component {
const vm: Component = this
if (Array.isArray(event)) {
for (let i = 0, l = event.length; i < l; i++) {
vm.$on(event[i], fn)
}
} else {
(vm._events[event] || (vm._events[event] = [])).push(fn)
// optimize hook:event cost by using a boolean flag marked at registration
// instead of a hash lookup
if (hookRE.test(event)) {
vm._hasHookEvent = true
}
}
return vm
}
複製代碼
$on
負責註冊函數,事件以數組形式存貯在vm
的_event
屬性上。$on第一個參數容許傳入字符串數組,數組的每一個成員對應的函數都是fn。 注意第一行定義了hookRE=/^hook:/
這個正則,這樣作的目的是:bash
vm.$on('hook:created', fn)
複製代碼
當註冊了一個hook:+聲明週期
的鉤子函數以後,vue內部會在調用組件options提供的聲明周期函數後還會調用一次用戶經過$on註冊的鉤子函數。app
$off
vm.$off([event, callback])
函數
Vue.prototype.$off = function (event, fn) {
var this$1 = this;
var vm = this;
// 若是未傳入任何參數,則刪除全部事件
if (!arguments.length) {
vm._events = Object.create(null);
return vm
}
// 數組形式循環刪除數組的每一項事件
// 對應$on以數據形式註冊函數
if (Array.isArray(event)) {
for (var i = 0, l = event.length; i < l; i++) {
this$1.$off(event[i], fn);
}
return vm
}
// 若是不存在該事件,則返回
var cbs = vm._events[event];
if (!cbs) {
return vm
}
// 若是存在該event,但未傳入鉤子函數,則將事件置空。
if (!fn) {
vm._events[event] = null;
return vm
}
if (fn) {
// specific handler
var cb;
var i$1 = cbs.length;
// 循環刪除事件數組對應的每一項
while (i$1--) {
cb = cbs[i$1];
// 注意這裏的fn是引用傳遞,對應的內存函數是一個
// 不然兩個單獨內存的函數沒法進行比較
if (cb === fn || cb.fn === fn) {
cbs.splice(i$1, 1);
break
}
}
}
return vm
};
複製代碼
$once
vm.$once(event, fn)
ui
Vue.prototype.$once = function (event, fn) {
var vm = this;
function on () {
vm.$off(event, on);
fn.apply(vm, arguments);
}
on.fn = fn;
vm.$on(event, on);
return vm
};
複製代碼
這裏的$once
其實是將傳入的event
事件作了一個攔截改寫,將fn鉤子函數改寫成on
函數,on
函數在調用時會先卸載改寫的事件,並經過必包調用傳入的原始鉤子函數fn
,注意這裏將fn
掛載在on
刪除上,是爲了在調用off
卸載事件時進行比較。this
$emit
vm.$emit(event, [...args])
spa
Vue.prototype.$emit = function (event) {
var vm = this;
var cbs = vm._events[event];
if (cbs) {
cbs = cbs.length > 1 ? toArray(cbs) : cbs;
// 獲取除event以外的全部參數
var args = toArray(arguments, 1);
// 循環調用事件數組的每一項
for (var i = 0, l = cbs.length; i < l; i++) {
try {
// 給事件this綁定爲vm
cbs[i].apply(vm, args);
} catch (e) {
handleError(e, vm, ("event handler for \"" + event + "\""));
}
}
}
return vm
};
}
複製代碼
$emit
做用是充當發佈者的角色觸發事件,而全部的事件會以數組形式存儲在vm的_event中。prototype
callhook
callhook
不算是vue event事件相關的成員函數,但vue的聲明周期函數都是經過callhook
函數調用,也算是充當發佈者的角色。code
function callHook (vm, hook) {
...
var handlers = vm.$options[hook];
var info = hook + " hook";
if (handlers) {
for (var i = 0, j = handlers.length; i < j; i++) {
invokeWithErrorHandling(handlers[i], vm, null, vm, info);
}
}
if (vm._hasHookEvent) {
vm.$emit('hook:' + hook);
}
...
}
複製代碼
首先,callHook
會先調用組件options
上掛載的聲明周期函數。在介紹$on
方法時,發現只要以hook:
註冊的聲明週期鉤子函數,會將_hasHookEvent
變爲true
,這時,再經過callhook
調用options
的聲明週期鉤子函數時,還會在調用以hook:
事件掛載在vm._event上的鉤子函數。
所以,當咱們想監聽聲明周期函數是否調用時,能夠經過vm.$on('hook:created', cb)
來實現。
文章內容若有錯誤,敬請諒解,但願能夠不吝賜教
轉載請註明出處,感謝