简单手写 EventBus

Huy大约 1 分钟javascriptjavascript

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...