js简单的发布/订阅

129 阅读1分钟
原文链接: zhuanlan.zhihu.com

vue项目中不同组件间通信一般使用vuex,通常情况下vuex和EventBus不应该混用,不过某些场景下不同组件间只有消息的交互,这时使用EventBus消息通知的方式就更合适一些。使用了一下new Vue()方式,但是想着自己实现一个,最初思路:

class EventBus {
  constructor () {
    /** event = {
          event1: [params]
        }
     **/
    this.events = {}
  }
  $emit (event, ...args) {
    this.events[event] = args
  }
  $on (event, fn) {
    fn(...(this.events[event]))
  }
  $off (event) {
    delete this.events[event]
  }
}
var bus = new EventBus()
bus.$emit('bus1', 1, 2, 3)
bus.$on('bus1', function (...args) {
  console.log('bus1----', ...args)
})

想当然的代码自然会出现想当然的结果:

1、$emit必须在$on之前

2、多次$emit只会监听的到一次

so继续改进:

class EventBus {
  constructor () {
    /** event = {
          event1: [fn, fn]
        }
     **/
    this.events = {}
  }
  $emit (event, ...args) {
    if (!this.events[event] || !this.events[event].length) return
    let fns = this.events[event]
    fns.forEach(fn => {
      fn.call(this, ...args)
    })
  }
  $on (event, fn) {
    if (!this.events[event]) this.events[event] = []
    this.events[event].push(fn)
  }
  $off (event) {
    delete this.events[event]
  }
}
var bus = new EventBus()
bus.$on('bus1', function (...args) {
  console.log('bus1----', ...args)
})
bus.$on('bus1', function (...args) {
  console.log('bus1----', ...args)
})
bus.$emit('bus1', 1,2,3)
bus.$emit('bus1', 4,5,6)

在$on里将回调函数push到数组中,然后在$emit里遍历这些fn并将$emit的参数绑定到每个fn