1. 事件概述
Vue 中的事件可以分爲 2 類:原生 DOM 事件、自定義事件。兩者在使用方式、用途、源碼處理的實現上存在區別。
使用方式:
原生 DOM 事件可用在原生 DOM 元素上,也可用在組件上(這種情況下,需使用.native
修飾符);自定義事件只能在組件上使用。
用途:
它們都具有事件的基本用途 – 界面與用戶交互;而自定義事件還經常用於父子組件之間的通信
。
源碼實現:
原生 DOM 事件的處理主要依靠原生的addEventListener
和removeEventListener
來完成;而自定義事件則是通過事件中心
的模型處理的。
2. 代碼實現基本事件中心
Vue 中的事件處理,主要有 vm.$on、vm.$off、vm.$emit、vm.$once 這四個方法:
vm.$on:
監聽當前實例上的自定義事件。
vm.$off:
移除自定義事件監聽器。
如果沒有提供參數,則移除所有的事件監聽器;
如果只提供了事件,則移除該事件所有的監聽器;
如果同時提供了事件與回調,則只移除這個回調的監聽器。
vm.$emit:
觸發當前實例上的事件。附加參數都會傳給監聽器回調。
vm.$once:
監聽一個自定義事件,但是隻觸發一次。一旦觸發之後,監聽器就會被移除。
下面是實現基礎功能的代碼部分:
class EventBus {
constructor() {
// 事件中心的核心
// 存儲所有的事件名稱以及對應的事件處理函數列表
this._events = {};
}
// vm.$on(event, callback)
// 根據事件名稱 event,將事件回調放進對應的列表
on(event, callback) {
(this._events[event] || (this._events[event] = [])).push(callback);
}
// vm.$off([event, callback])
off() {
let _args = [...arguments];
let length = _args.length;
switch (length) {
case 0: // 移除所有的事件的回調函數
for (let event in this._events) {
this._events[event] = [];
}
break;
case 1: // 移除特定事件的事件回調列表
let _event0 = _args[0];
for (let event in this._events) {
if (_event0 === event) {
this._events[event] = [];
}
}
break;
default: // 移除指定特定事件下的特定的事件回調
let _event = _args[0];
let _callback = _args[1];
for (let event in this._events) {
if (_event === event) {
this._events[event].map((item, index) => {
if (item.toString() === _callback.toString()) {
this._events[event].splice(index, 1);
}
});
}
}
}
}
// vm.$emit(eventName, [...args])
// 找到指定事件名稱的回調函數列表,遍歷且執行回調
emit(eventName) {
let callbacks = this._events[eventName];
let params = [...arguments].slice(1);
callbacks &&
callbacks.map((_callback) => {
_callback(...params);
});
}
// vm.$once(event, callback)
// 根據事件名稱 event,將事件回調放進對應的列表;且該回調被執行一次後,就會移除
once(event, callback) {
let that = this
function _on() {
// 移除事件處理回調函數
that.off(event, _on);
// 使用參數,調用回調
callback.apply(that, arguments);
}
that.on(event, _on);
}
}
接下來,創建出 EventBus 實例後,就可以使用功能了,下面是一些簡單的測試: