简单手写 EventBus
大约 1 分钟
EventBus 是一种事件发布/订阅模式的设计模式。
先写一个简单版:
class EventBus {
constructor() {
this.events = {}
}
on(eventName, callback) {
this.events[eventName] = callback
}
off(eventName) {
delete this.events[eventName]
}
emit(eventName, ...args) {
if (this.events.hasOwnProperty(eventName)) {
this.events[eventName].apply(null, args)
}
}
}
// 测试
function fn1(a, b) {
console.log('fn1', a, b)
}
function fn2(a, b) {
console.log('fn2', a, b)
}
const eventBus = new EventBus()
eventBus.on('click', fn1)
eventBus.on('click2', fn2)
eventBus.emit('click', 1, 2)
eventBus.emit('click2', 3, 4)
eventBus.off('click') // 卸载
eventBus.emit('click', 5, 6) // 无打印
eventBus.emit('click2', 7, 8)
自定义事件的要点有:
on
事件,注册监听once
事件,只执行一次off
事件,注销监听emit
事件,触发监听
/**
* @description Event Bus 事件总线
* {
* 'key': [
* {fn: string, isOnce: boolean}
* ]
* }
*/
class EventBus {
private events: {
[key: string]: Array<{ fn: Function; isOnce: boolean }>
}
constructor() {
this.events = {}
}
on(type: string, fn: Function, isOnce: boolean = false) {
const event = this.events[type]
if (event == null) this.events[type] = []
this.events[type].push({ fn, isOnce })
}
once(type: string, fn: Function) {
this.on(type, fn, false)
}
off(type: string, fn?: Function) {
if (!fn) {
// 解绑所有 type 类型的函数
this.events[type] = []
} else {
// 解绑单个 fn
this.events[type] = this.events[type].filter((item) => {
item.fn !== fn
})
}
}
emit(type: string, ...args: any[]) {
const fnList = this.events[type]
if (fnList == null) return
// 注意是否有 once, 执行一次则需要过滤
this.events[type] = fnList.filter((item) => {
const { fn, isOnce } = item
fn(...args)
if (isOnce) return true
return false
})
}
}
// 功能测试
const e = new EventBus()
function fn1(a: any, b: any) {
console.log('fn1', a, b)
}
function fn2(a: any, b: any) {
console.log('fn2', a, b)
}
function fn3(a: any, b: any) {
console.log('fn3', a, b)
}
e.on('key1', fn1)
e.on('key2', fn2)
e.once('key3', fn3)
e.emit('key1', 10, 20) // 触发 fn1 fn2 fn3
e.off('key1', fn1)
e.emit('key1', 100, 200) // 不再触发
e.emit('key2', 200, 400)
e.emit('key3', 300, 600) // 触发一次
e.emit('key3', 400, 800) // 不再触发
Loading...