事件总线
提供一个事件总线,给其他的组件或模块以监听和修改数据的权利,它具体做的事情可以有以下几种
- 提供监听某个事件的接口
- 提供取消监听的接口
- 触发事件的接口(可传递数据)
- 触发事件后会自动通知监听者
下面介绍一下如何用代码实现事件总线的效果
首先在全局新建一个
eventBus.js
文件,此文件是与
main.js
并列等级的,我们希望它导出一个事件总线,其实就是一个对象,里边包含了事件总线的相关配置内容,含有方法接口
/*
* 事件总线
* 具体完成上述的四个功能(其中第四个功能是通过前三个完成的)
* 导出对象,内部包含一些方法,供外部调用
*/
/*
给一个全局的数组,每次有添加监听事件的时候,就往内部添加一个对象,其属性名是事件名,属性值是一个数组,
里边是对此事件进行监听的处理函数(因为可能有很多组件或JS模块对该事件进行监听),这里可以使用new Set()
集合进行自动的去重操作!
[
{'event1': [ handler1, handler2 ]},
{'event2': [ handler1 ]},
]
*/
const $listeners = [];
export default {
// 开启某个事件的监听
$on(eventName, handler){
if(!$listeners[eventName]){
$listeners[eventName] = new Set();
}
$listeners[eventName].add(handler);
},
// 取消某个事件的监听
$off(eventName, handler){
if(!$listeners[eventName]){
return;
}
$listeners[eventName].delete(handler);
},
// 触发某个事件(可以传参),通过剩余参数接受
$emit(eventName, ...args){
if(!listeners[eventName]){
return;
}
listeners[eventName].forEach((handler)=>{
handler(...args);
});
}
}
该模块完成之后,我们去到
main.js
文件中测试,测试代码如下所示
// 测试事件总线接口
import eventBus from "./eventBus";
function handler1(data){
console.log("handler1", data);
}
function handler2(data){
console.log("handler2", data);
}
eventBus.$on("event1", handler1);
eventBus.$on("event1", handler2);
eventBus.$on("event2", handler1);
window.eventBus = eventBus;
window.handler1 = handler1;
window.handler2 = handler2;
简单解读一下,这段代码相当于在事件总线上添加了两个对象,
第一个是关于事件
event1
的,里面包含了两个处理函数
handler1
和
handler2
,存放在一个数组中,并将其赋值给事件
event1
作为该事件的属性值
第一个是关于事件
event2
的,里面包含了一个处理函数
handler1
,存放在一个数组中,并将其赋值给事件
event2
作为该事件的属性值
最后一部分是为了给全局注册一下事件总线,方便后续在控制台调试
如图所示,运行如下代码,可以看到当使用事件总线抛出一个
event1
事件的时候,同时运行了两个处理函数,并且将参数数据各自代入到了处理函数中,
当使用事件总线抛出一个
event2
事件的时候,运行了
handler1
处理函数,并且将参数
456
代入到了处理函数中
下面测试一下取消事件监听的函数,可以看见,在运行了
eventBus.$off("event1", handler1)
之后,当事件总线在此抛出
event1
事件的时候,就会仅仅运行
handler2
处理函数了,也就是说把
handler1
在事件
event1
的处理函数集合中删除掉了,但是对于事件
event2
的事件处理函数没有影响。
至此,说明上述事件总线的功能已经完成,并能成功实现我们所期望的效果。
但是这里为什么使用
$emit
,
$on
等等如此接近于
vue
的实例成员属性和方法呢,那是因为,在一般的开发当中,其实常常利用一个新的
vue
实例来完成上述效果,因为一个
vue
实例内置了上述几个方法。
于是,我们在事件总线模块
eventBus.js
中便可以如下写
import Vue from "vue";
export default new Vue({});
就行了,因为
vue
组件实例对象中就内置了
$on
,
$off
,
$emit
的方法,因此原封不动的就可以直接调用原来的测试代码。