概述
事件总线是个啥呢?学术性的解说是:事件总线是实现基于事件驱动模式的方式之一,或者可以将其称为“Broker Topology”。事件发送者将事件消息发送到一个中心broker 上,事件订阅者向中心broker 订阅和接收事件,然后再处理接收到的事件。当然,订阅者不仅可以接收和消费事件,它们本身也可以创建事件,并将它们发送到事件总线上。
在前端中主要体现在非父子组件间的通信(当然,父子组件也可以,只是父子组件中我们不会这样做)
事件总线是一种应用程序设计模式,它允许组件向其他组件发布和订阅事件。事件总线通常是一个中心化的架构,允许不同的组件在不彼此直接通信的情况下进行信息交流。当一个组件发布一个事件时,事件总线会将该事件传递给所有已经订阅该事件的组件。这种模式可以帮助解耦不同组件之间的依赖关系,从而使代码更加模块化、易于维护和扩展。在很多框架和库中都有实现事件总线的功能,例如Vue.js中的Vue实例和React中的Redux。
你要是觉得不好理解,我觉得可以给你举个形象的比喻。比如说五月天即将来到你的城市开演唱会,你想买票去看,也就是你(订阅者)要和门票(发布者)之间产生关联,票务平台 – 大麦,票牛,官方公众号平台等等就充当了事件总线的角色。但是开票就秒光,这时候一个让人又爱又恨的职业就诞生了 — 黄牛。你买不到票,但可以确定的是黄牛手里一定有票,你只需要付出高溢价就能入场,至于中间的辗转各个平台抢购,几点抢,什么座位,内场还是外场还是山顶等等你都不用关心,多少溢价对应多少等级的门票。这中间黄牛就充当了事件总线的功能。当然,这只是一个玩笑,希望大家不要当真,条件允许的情况下大家能在正规的票务平台买就在平台买,不要买黄牛的,黄牛有风险,入手需谨慎!!! 从以上描述就可以看出,事件总线就和中介差不多(当然,只是类比),三个角色,买方,卖方,中间平台,其中买卖双方的角色可以互换。
好了,废话了这么多,言归正传,看代码吧!
class EventBus {
constructor() {
// 用一个对象来保存监听的事件
this.eventBus = {}
}
// 监听事件
on(eventName, eventCallback, thisArg) {
let handlers = this.eventBus[eventName]
// 针对第一次取到的监听事件为空进行处理
if (!handlers) {
handlers = []
// 引用赋值
this.eventBus[eventName] = handlers
}
// 此时this.eventBus[eventName]也被赋值了,因为他和handlers指向同一块地址
handlers.push({
eventCallback,
thisArg
})
}
// 取消监听事件
off(eventName, eventCallback) {
const handlers = this.eventBus[eventName]
if (!handlers) return
const newHandlers = [...handlers]
for (let i = 0; i < newHandlers.length; i++) {
const handler = newHandlers[i]
if (handler.eventCallback === eventCallback) {
const index = handlers.indexOf(handler)
handlers.splice(index, 1)
}
}
}
// 触发事件
emit(eventName, ...payload) {
const handlers = this.eventBus[eventName]
if (!handlers) return
handlers.forEach(handler => {
handler.eventCallback.apply(handler.thisArg, payload)
})
}
}
const eventBus = new EventBus()
// main.js
eventBus.on("abc", function() {
console.log("监听abc1", this)
}, {name: "why"})
const handleCallback = function() {
console.log("监听abc2", this)
}
eventBus.on("abc", handleCallback, {name: "why"})
// utils.js
eventBus.emit("abc", 123)
// 移除监听
eventBus.off("abc", handleCallback)
eventBus.emit("abc", 123)
应用场景
用于跨文件,跨组件之间的通信