linche0859
10/6/2019 - 1:05 PM

Event Bus

用途

component執行方法或傳遞資料

bus.js

export default function Bus(vue) {
  // 存放所有component的 method
  this.handles = {
    // event: [function, function,...]
  }
  // 存放所有component的 uid和 method
  this.eventUidMap = {
    // uid:{
    //   event:[function, function]
    // }
  }
  this.$on = (event, callback, vm) => {
    if (!this.handles[event]) this.handles[event] = []
    if (callback instanceof Function) this.handles[event].push(callback)
    if (vm instanceof vue) this.setEventUidMap(vm._uid, event, callback)
  }
  this.setEventUidMap = (uid, event, callback) => {
    if (!this.eventUidMap[uid]) this.eventUidMap[uid] = {}
    if (!this.eventUidMap[uid][event]) this.eventUidMap[uid][event] = []
    this.eventUidMap[uid][event].push(callback)
  }
  this.$off = (event, callback) => {
    if (!this.handles[event]) return
    // delete object property
    if (!callback) delete this.handles[event]
    else if (callback instanceof Function) {
      let len = this.handles[event].length
      for (let i = 0; i < len; i++) {
        let cb = this.handles[event][i]
        // delete function
        if (cb === callback) this.handles[event].splice(i, 1)
      }
    }
  }
  // 刪除component的 uid
  this.$offByUid = uid => {
    let eventObj = this.eventUidMap[uid] || {}
    // 遍遞每一個event
    Object.keys(eventObj).forEach(event => {
      // 遍地每一個event的function
      eventObj[event].forEach(cb => {
        this.$off(event, cb)
      })
      // delete all event
      // delete eventObj[event]
    })
    delete this.eventUidMap[uid]
  }
  this.$emit = (event, ...args) => {
    // return的資料都丟來這
    // 如果沒 return,則回傳undefined
    let result = []
    if (this.handles[event]) {
      let len = this.handles[event].length
      for (let i = 0; i < len; i++) {
        result.push(this.handles[event][i](...args))
      }
    }
    return result
  }
  return this
}

main.js

import Bus from '@/bus.js'

let eventBus = {
  install(vue) {
    let bus = new Bus(vue)
    // 等同是Vue.prototype.$eventBus = ...
    // 因為要做成唯讀
    Object.defineProperties(Vue.prototype, {
      $eventBus: {
        get: () => bus
      }
    })
    // 所有的component,都可以有mixin內的功能
    Vue.mixin({
      beforeDestroy() {
        // this是VueComponent
        this.$eventBus.$offByUid(this._uid)
      }
    })
  }
}
// 預設把Vue傳進去
// 因為Vue.prototype.$eventBus了,VueComponent同時也有「$eventBus」
Vue.use(eventBus)

兄層註冊事件

export default {
  name: 'levelOne',
  data() {
    return {
      list: ['html', 'css', 'javascript']
    }
  },
  components: {
    LevelTwo
  },
  methods: {
    eventHandler(...arg) {
      console.log(arg)
      console.log(this.list)
    },
    getListHandler() {
      return { list: this.list }
    }
  },
  created() {
    // 新增事件到event bus
    this.$eventBus.$on('levelOneEvent', this.getListHandler, this)
    this.$eventBus.$on('levelOneEvent', this.eventHandler, this)
  }
}

弟層接收呼叫事件和接收資料

export default {
  name: 'levelTwo',
  data() {
    return {
      list: []
    }
  },
  methods: {
    displayListHandler() {
      this.$eventBus.$emit('levelOneEvent').forEach(item => {
        // 沒有回傳值的,會是undefined
        if (item) {
          Object.keys(item).forEach(key => {
            if (key === 'list') this.list = item[key]
          })
        }
      })
    }
  }
}