文章目录
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 实例后,就可以使用功能了,下面是一些简单的测试: