自定义事件总线

201 阅读1分钟

学习了coderwhy的JavaScript高级语法视频课的笔记

如有错误或者不合适的地方,敬请见谅,欢迎指出和拓展,谢谢各位了

  • 自定义事件总线属于一种观察者模式,其中包括三个角色:
    • 发布者(Publisher):发出事件(Event);
    • 订阅者(Subscriber):订阅事件(Event),并且会进行响应(Handler);
    • 事件总线(EventBus):无论是发布者还是订阅者都是通过事件总线作为中台的。
  • 我们可以选择一些第三方的库:
    • Vue2默认是带有事件总线的功能;
    • Vue3中推荐一些第三方库,比如mitt。
  • 当然我们也可以实现自己的事件总线:
    • 事件的监听方法on;
    • 事件的发射方法emit;
    • 事件的取消监听off。
class EventBus {
  constructor() {
    this.eventCallbacks = {}
  }

  on(eventName, eventCallback, thisArg) {
    let handlers = this.eventCallbacks[eventName]
    //   如果handlers没有值,则赋给它一个空数组
    if (!handlers) {
      handlers = []
      this.eventCallbacks[eventName] = handlers
    }
    // 把监听事件放入对应的eventName数组
    handlers.push({
      eventCallback,
      thisArg
    })
  }

  emit(eventName, ...Arg) {
    const handlers = this.eventCallbacks[eventName]
    if (!handlers) return
    handlers.forEach(handler => {
      handler.eventCallback.apply(handler.thisArg, Arg)
    })
  }

  off(eventName, eventCallback) {
    const handlers = this.eventCallbacks[eventName]
    if (!handlers) return
    // 一个数组[1,2,2,3],对应的索引是0,1,2,3;
    // 如果要删除2元素,当遍历到索引为1时,则符合删除,删除后数组为[1,2,3];
    // 遍历下一个则索引为2,此时元素为3,所以第二个2无法删除;
    // 所以定义一个新数组遍历找索引。
    const newHandlers = [...handlers]
    for (let i = 0; i < newHandlers.length; i++) {
      if (newHandlers[i].eventCallback === eventCallback) {
        const index = handlers.indexOf(newHandlers[i])
        //splice()改变原数组
        handlers.splice(index, 1)
      }
    }
  }
}

const eventBus = new EventBus()

eventBus.on(
  'abc',
  (...res) => {
    console.log('eventBus.on监听事件打印111---' + res)
  },
  { name: 'this的指向' }
)

const fn = () => {
  console.log('eventBus.on监听事件打印222')
}
eventBus.on('abc', fn, { name: 'this的指向222' })

eventBus.emit('abc', 123, 456)

// 移除指定的监听事件
eventBus.off('abc', fn)

eventBus.emit('abc', 123, 456)