使用Vuex的全球事件总线 - 始终通知订户

Joh*_*han 11 javascript vue.js vuex

我一直在Vue使用全球事件总线很长一段时间 - 就像const bus = new Vue().工作正常,但订阅的处理可能会变得非常冗长.

假设我订阅了一个组件中的事件:

mounted() {
  bus.$on('some.event', callback)
}
Run Code Online (Sandbox Code Playgroud)

我必须跟踪回调并妥善处理它beforeDestroy.使用全局mixin可以稍微简化一下,但是由于我正在使用<keep-alive>,我必须区分订阅mountedactivated回调.

所以我认为我会给Vuex一个管理这个的机会,因为观察者被框架处理掉了.我想出了下面的建议.

只要发布了对象或数组,似乎工作正常.原始数据似乎不会触发反应,尽管被包裹在外部对象中,即{ data: 123 }

我正在寻找有关通知订阅者的替代解决方案.到目前为止我所看到的只是内部notify方法,使用起来感觉不太安全.

eventstore.js

import Vue from 'vue'

const state = {
  events: {}
}

const actions = {
  publish({commit}, payload) {
    commit('publish_event', payload)
  }
}

const mutations = {
  publish_event(state, payload) {
    if(!state.events[payload.key]) {
      Vue.set(state.events, payload.key, { data: payload.data })
    } else {
      state.events[payload.key] = { data: payload.data }
    }
  }
}

const getters = {
  events: state => state.events
}

export default {
  state,
  actions,
  mutations,
  getters
}
Run Code Online (Sandbox Code Playgroud)

globalmixin.js

methods: {
  publish(key, data) {
    this.$store.dispatch('publish', { key, data })
  }
}
Run Code Online (Sandbox Code Playgroud)

somecomponent.vue

function mapEventGetters(eventKeys) {
  return _.reduce(eventKeys, (result, current) => {
    result[current] = function() {
      return  _.get(this, `$store.getters.events.${current}.data`)
    }
    return result
  }, {})
}
Run Code Online (Sandbox Code Playgroud)
computed: {
  ...mapEventGetters(['foo_bar'])
},
watch: {
  'foo_bar'(value) {
    console.log(`foo_bar changed to ${value}`)
  }
}
Run Code Online (Sandbox Code Playgroud)

itt*_*tus 2

您可以使用 deepCopy (例如JSON.parse(JSON.stringify()))来确保数据是反应性的

const mutations = {
  publish_event(state, payload) {
    if(!state.events[payload.key]) {
      state.events[payload.key] = { data: payload.data }
    } else {
      state.events[payload.key] = Object.assign({}, state.events[payload.key], { data: payload.data })
    }
    state.events = JSON.parse(JSON.stringify(state.events))
  }
}
Run Code Online (Sandbox Code Playgroud)

在上面的组件中,您正在监听foo_bar观察者。Vue 观察程序仅适用于组件数据(来自datacomputedvuex)。

您可以按如下方式重新定义数据componentData。您可以使用mapGetters更短的语法:

<script>
  import { mapGetters } from 'vuex'
  export default {
    ...mapGetters(['events']),
    computed: {
      componentData () {
        const eventKeys = ['foo_bar']
        return _.reduce(eventKeys, (result, current) => {
          result[current] = function() {
            return  _.get(this, `events.${current}.data`)
          }
          return result
        }, {})
      }
    },
    watch: {
      componentData: function (newVal, oldVal) {
        ...
      }
    }
  }
</script>
Run Code Online (Sandbox Code Playgroud)