前言
- 设计模式其实就是编程中的23种经典套路,它们在特定场景下能帮助我们编写出更加优雅和高效的代码。
- 虽然设计模式对每位开发者来说都至关重要,但现有的书籍往往以Java为例进行讲解,这可能让我们这些“切图仔”感到不够友好。
- 因此,我后续会写一篇专门针对我们这些“切图仔”的设计模式文章,并且会列出具体的应用场景,感兴趣的话关注一波再走:# 以 JavaScript 浅谈常见的几种设计模式
- 今天主要讲的事件总线(eventBus),其实也是设计模式中的发布订阅模式
- 发布订阅模式和观察者模式本质上是一样的,所以很多地方也就直接把两者看成一种设计模式了
- 观察者模式是一个对象有多个依赖
- 而发布订阅模式其实是引入了一个中间层,来进行注册和通知
- 其实 eventBus 就是实现了发布订阅模式
- eventBus就是这个中间层,可以调用它的on方法进行注册(也就是订阅),调用它的emit方法进行通知(也就是发布)
事件总线的具体实现和使用方法
-
手写事件总线的具体步骤
- 其实核心思想就是当开发者给on方法传入“被监听事件名”和“事件触发要做的具体操作”之后,将它们存在一个对象中
- 开发者会在“被监听事件”中调用emit方法,当“被监听事件”触发了之后,那么就会调用emit方法,我们就可以通过调用emit事件时传入的“被监听事件名”找到被存在对象中的“事件触发要做的具体操作”,然后对其调用即可
// 封装一个实现了事件总线具体操作的类
class zdEventBus {
constructor() {
this.events = {}
}
// 事件的监听方法
on(eventName, eventFn) {
let eventKey = this.events[eventName]
// 因为考虑到一个“被监听事件名”可能会对应多个操作,所以将操作都放在一个数组中,最后遍历数组,执行操作即可
if (!eventKey) {
this.events[eventName] = []
}
this.events[eventName].push(eventFn)
}
// 时间的取消监听方法
// 开发者如果想要删除某个“被监听事件名”对应的某个“事件触发要做的具体操作”,调用该方法即可
off(eventName, eventFn) {
let eventKey = this.events[eventName]
if (!eventKey) return
eventKey.splice(eventKey.indexOf(eventFn), 1)
// 如果这个“被监听事件名”对应的数组已经为空了,那么就将这个key从对象中删掉
if (eventKey.length === 0) {
Reflect.deleteProperty(this.events, eventName)
}
}
// 事件的发射方法
emit(eventName, ...args) {
let eventKey = this.events[eventName]
if (!eventKey) return
eventKey.forEach(fn => fn(...args));
}
}
- 事件总线的使用方法
- 首先,拿到实现事件总线的类zdEventBus之后,在aside板块中通过它的实例对象调用它的on方法,需要传入两个参数,第一个参数代表要监听事件的名字,第二个参数则是,如果监听的事件被触发之后,要做的操作
- 其次,就是在被监听的那个事件触发的时候,也就是在nav板块中btn的onclick事件被触发后,调用一下事件总线的实例对象的emit方法,使事件总线能够知道,这个事件现在被触发了
<body>
<button class="nav-btn">按钮</button>
<script>
// 拿到事件总线这个类的实例对象
const eventBus = new zdEventBus()
// aside板块
// 因为在监听完成之后还要调用off方法取消监听,所以得将方法提取到外面,不能使用匿名函数
const click1 = function(name, age, height) {
console.log("nav-click发生了_01", name, age, height)
}
eventBus.on("nav-click", click1)
eventBus.off("nav-click", click1)
const click2 = function() {
console.log("nav-click发生了_02")
}
eventBus.on("nav-click", click2)
eventBus.off("nav-click", click2)
eventBus.on("footer-click", function() {
console.log("footer-click发生了_01")
})
console.log(eventBus.events)
// nav板块
const btnEl = document.querySelector(".nav-btn")
btnEl.onclick = function() {
console.log("btnEl发生点击了")
eventBus.emit("nav-click", "Judy", 18, 1.88)
}
</script>
</body>
总结
- 其实说白了,on方法就是将要监听的事件名称以及对应的事件处理函数交给 eventBus 进行存储
- 然后在需要发出事件的地方,就调用 emit 方法并将要触发的事件名称传入
- 在 emit 方法中其实就是在根据传入的事件名称去调用对应的事件处理函数