事件总线
事件总线
Event bus通常作为多模块间的通信机制,如:Vue中可以通过Event bus在多个组件中传递数据。
Event Bus本质是采用发布订阅模式
通常包含一下几个功能
- on
- 订阅事件,传入事件名和事件的回调
- emit
- 发布事件,传入事件名即可
- off
- 取消事件,只传入事件名,默认取消所有事件,如果传入第二个参数:需要取消的事件,则只取消传入的事件
- once
- 只订阅一次事件
使用
Map收集事件
class EventBus {
constructor() {
this.events = new Map()
}
/**
* 订阅事件
* @param {string} eventName
* @param {Function} cb
*/
on(eventName, cb) {
if (typeof cb !== 'function') {
throw new Error('cb is not a function')
}
if (!this.events.has(eventName)) {
this.events.set(eventName, [])
}
const cbs = this.events.get(eventName)
cbs.push({
handle: cb
})
}
/**
* 发布事件
* @param {string} eventName
*/
emit(eventName) {
if (this.events.has(eventName)) {
const cbs = this.events.get(eventName)
cbs.forEach((cb) => {
cb.handle(...Array.prototype.slice.call(arguments, 1))
if (cb.once) {
// 取消订阅
this.off(eventName, cb.handle)
}
})
}
}
/**
* 取消事件
* @param {string} eventName
* @param {Function|undefined} cb
* @returns
*/
off(eventName, cb) {
if (!this.events.has(eventName)) {
return
}
if (cb === undefined) {
// 清除所有
this.events.delete(eventName)
} else {
const cbs = this.events.get(eventName)
const res = cbs.filter((item) => {
return item.handle !== cb
})
this.events.set(eventName, res)
}
}
/**
* 订阅一次
* @param {string} eventName
* @param {Function} cb
*/
once(eventName, cb) {
if (!this.events.has(eventName)) {
this.events.set(eventName, [])
}
const cbs = this.events.get(eventName)
cbs.push({
handle: cb,
once: true
})
}
}