代码之家  ›  专栏  ›  技术社区  ›  Johan

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

  •  10
  • Johan  · 技术社区  · 6 年前

    const bus = new Vue() . 工作正常,但是,订阅的处理可能会变得非常冗长。

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

    mounted() {
      bus.$on('some.event', callback)
    }
    

    我必须跟踪回拨并妥善处理 beforeDestroy <keep-alive> ,我必须区分在 mounted activated 回拨。

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

    notify 方法,使用起来不太安全。

    事件商店.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
    }
    

    全球混合素.js

    methods: {
      publish(key, data) {
        this.$store.dispatch('publish', { key, data })
      }
    }
    

    somecomponent.vue文件

    function mapEventGetters(eventKeys) {
      return _.reduce(eventKeys, (result, current) => {
        result[current] = function() {
          return  _.get(this, `$store.getters.events.${current}.data`)
        }
        return result
      }, {})
    }
    
    computed: {
      ...mapEventGetters(['foo_bar'])
    },
    watch: {
      'foo_bar'(value) {
        console.log(`foo_bar changed to ${value}`)
      }
    }
    
    3 回复  |  直到 6 年前
        1
  •  2
  •   ittus    6 年前

    您可以使用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))
      }
    }
    

    foo_bar 在观察者。 Vue watcher 仅使用零部件数据(从 data computed vuex

    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>
    
        2
  •  1
  •   Ismoil Shifoev    6 年前

    这个API将破坏Vuex的数据流,这是Vuex的核心概念。客户机将能够在Vuex中的任何地方改变/读取存储状态。

    老实说,这种方法不需要在Vuex中实现,因为它只是一个事件发射器。我建议您在操作中使用一些事件发射器(可能是空的Vue实例)。

    export const emitter = new Vue()
    
    export default {
      // ...
    
      actions: {
        // should be called when the store is initialized
        // to observe events
        observe({ dispatch, commit }) {
          emitter.$on('some-event', () => {
            commit('someEvent')
          })
    
          emitter.$on('other-event', () => {
            dispatch('otherEvent')
          })
        },
    
        // notify some event in action
        notify({ state }) {
          emitter.$emit('notify', state.someValue)
        }
      }
    }
    

    当我在github中搜索时,它解决了我的问题一次。我会帮助你的。谢谢!!

        3
  •  0
  •   mgibson    5 年前

    打电话 Vue.set

    Vue.set(state.events, payload.key, {})
    Vue.set(state.events[payload.key], 'data', payload.data)
    

    您还可以将其包装到一个实用函数中,该函数使用

        4
  •  -1
  •   Vladislav Ladicky    6 年前

    你能试试这个让我知道在这两种情况下是否都触发了反应吗?

    首先,用outer对象移除这个不必要的包装,并将有效负载作为简单的key/value对象发送,其中包含所需的事件键和该键的数据:

    {
      someKey: 123
    }
    

    其次,发送一些嵌套数据:

    {
      someKey: {
        nested: 'Value'
      }
    }
    

    const mutations = {
      publish_event(state, payload) {
        // Instead of the previous code, just "patch"
        // the state.events with the payload content.
        state.events = { ...state.events, ...payload }
      }
    }
    

    不要忘记改进mapEventGetters函数,因为数据不再嵌套在“data”属性中。

    PS:但就我个人而言,我不明白为什么不将Vuex与特定的getter一起使用,因为它是有效的,它会触发与基元类型的反应:

    存储/索引.js

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    const state = {
      events: {}
    }
    
    const actions = {
      publish({commit}, payload) {
        commit('publish_event', payload)
      }
    }
    
    const mutations = {
      publish_event(state, payload) {
        state.events = { ...state.events, ...payload }
      }
    }
    
    const getters = {
      fooBar: state => state.events.fooBar || ''
    }
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state,
      actions,
      mutations,
      getters
    })
    

    主要.js

    import Vue from 'vue'
    import App from '@/App'
    import store from '@/store'
    
    new Vue({
      store,
      render: h => h(App)
    }).$mount('main')
    

    一些成分

    <template>
      <span>{{ fooBar }}</span>
    </template>
    
    import { mapGetters, mapActions } from 'vuex'
    
    export default {
      name: 'SomeComponent',
    
      computed: {
        ...mapGetters(['fooBar'])
      },
    
      methods: {
        ...mapActions(['publish'])
      },
    
      created () {
        setTimeout(() => {
          publish({
            fooBar: 123
          })
        }, 3000)
      }
    }