发布订阅模式:订阅者,发布者,信号中心
我们假定,存在一个“信号中心”,某个任务执行完成,就向信号中心"发布"(publish)一个信号,其它任务可以向信号中心“订阅”(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe
pattern)
家长向学生所在的班级订阅了获取学生考试成绩的事件,当老师公布学生的成绩后,就会自动通知学生的家长。
在整个案例中,学生所在的班级为信号中心,老师为发布者,家长为订阅者
Vue 的自定义事件就是基于发布订阅模式来实现的。
下面通过Vue中兄弟组件通信过程,来理解发布订阅模式
// eventBus.js // 事件中心 let eventHub=new Vue() //ComponentA.vue
addTodo:function(){ //发布消息(事件)
eventHub.$emit('add-todo',{text:this.newTodoText}) this.newTodoText='' }
//ComponentB.vue //订阅者 created:function(){ //订阅消息(事件)
eventHub.$on('add-todo',this.addTodo) }
通过以上代码,我们可以理解发布订阅模式中的核心概念。
下面我们模拟Vue中的自定义事件的实现
下面我们先来做一个基本的分析:
先来看如下代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta
name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vue 自定义事件</title> </head> <body> <script
src="./js/vue.js"></script> <script> //Vue自定义事件 let vm = new
Vue(); //注册事件(订阅消息) vm.$on("dataChange", () => {
console.log("dataChange"); }); vm.$on("dataChange", () => {
console.log("dataChange"); }); //触发事件(发布消息)
vm.$emit("dataChange"); </script> </body> </html>
通过上面的代码,我们可以看到$on实现事件的注册,而且可以注册多个事件,那么我们可以推测在其内部有一个对象来存储注册的事件,对象的格式为:
{'click':[fn1,fn2],'change':[fn]}
以上格式说明了,我们注册了两个事件,分别为click与change.
下面我们根据以上的分析过程,来模拟实现自定义事件。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta
name="viewport" content="width=device-width, initial-scale=1.0" />
<title>发布订阅模式</title> </head> <body> <script> class EventEmitter {
constructor() { // {'click':[fn1,fn2],'change':[fn]} //
存储事件与处理函数的对应关系 this.subs = {}; } //注册事件
//第一个参数为事件名称 // 第二个参数为处理函数 // 将对应的处理函数添加到subs对象中
$on(eventType, fn) {
//判断对应的eventType是否有相应的处理函数,如果有,直接添加到数组中,如果没有返回一个空数组。 if
(!this.subs[eventType]) { this.subs[eventType] = []; }
this.subs[eventType].push(fn); } //触发事件 $emit(eventType)
{ if (this.subs[eventType]) {
this.subs[eventType].forEach((handler) => { handler();
}); } } } //测试代码 let em = new EventEmitter();
em.$on("click", () => { console.log("click1"); });
em.$on("click", () => { console.log("click2"); });
em.$emit("click"); </script> </body> </html>