js eventBus 事件总线(发布订阅模式)
事件总线:一种集中式事件处理机制,允许不同的组件之间进行彼此通信而又不需要相互依赖,达到一种解耦的目的。
class EventEmitter {
constructor() {
this.cache = {}
}
on(name, fn) {
if (this.cache[name]) {
this.cache[name].push(fn)
} else {
this.cache[name] = [fn]
}
}
emit(name, ...args) {
const tasks = this.cache[name] && this.cache[name].slice() // 创建副本,如果回调函数内继续注册相同事件,会造成死循环
if (tasks) {
for (const fn of tasks) {
fn(...args)
}
}
}
once(name, fn) {
const onceFn = (...args) => {
fn(...args)
this.off(name, onceFn)
}
onceFn.callback = fn
this.on(name, onceFn)
}
off(name, offFn) {
if (!offFn) {
delete this.cache[name] // 没有指明要关闭哪个监听回调,就清空所有
} else {
const stask = this.cache[name]
if (stask) {
const index = stask.findIndex(fn => fn === offFn || fn.callback === offFn)
if (index >= 0) {
stask.splice(index, 1)
}
}
}
}
}
测试示例:
const eventBus = new EventEmitter()
const fn1 = function (name, age) {
console.log(`fn1, ${name} ${age}`)
}
const fn2 = function (name, age) {
console.log(`fn2, ${name} ${age}`)
}
console.log('%c测试 emit---', 'color:blue')
eventBus.on('test', fn1)
eventBus.on('test', fn2)
eventBus.emit('test', '小明', 10)
console.log('%c测试 once---', 'color:blue')
eventBus.once('onceTest', fn1)
eventBus.once('onceTest', fn2)
eventBus.emit('onceTest', '小明', 10)
eventBus.emit('onceTest', '小明', 10) // 此 emit 不会起效,因为 once 中已经清空了监听
console.log('%c测试 off---', 'color:blue')
eventBus.off('test', fn1)
eventBus.emit('test', '小明', 10) // 此 emit, fn1 不会起效,fn2 仍然有效
console.log('%c再次测试 off---', 'color:blue')
eventBus.on('test', fn1)
eventBus.on('test', fn2)
eventBus.off('test')
eventBus.emit('test', '小明', 10) // 此 emit 不会起效,因为没有指明要关闭哪个监听回调,off 清空所有