我在Vue中使用全球事件总线已经有一段时间了-类似于const bus = new Vue()
。效果很好,但是订阅的处理可能会变得很冗长。
假设我订阅了一个组件中的事件:
mounted() {
bus.$on('some.event', callback)
}
我将不得不跟踪回调并将其正确放置在beforeDestroy
中。使用全局混合可以稍微简化此操作,但是由于我使用的是<keep-alive>
,因此我必须区分在mounted
和activated
回调中进行的订阅。
所以我认为我会给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
}
globalmixin.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}`)
}
}
答案 0 :(得分: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))
}
}
在上面的组件中,您正在监听器中监听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>
答案 1 :(得分:0)
此API将中断Vuex的数据流,这是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中搜索时,它解决了我的问题。可以帮助您。谢谢!
答案 2 :(得分:0)
在对象上调用Vue.set
不会为对象内部的数据增加观察者/反应性。这需要一个额外的Vue.set
Vue.set(state.events, payload.key, {})
Vue.set(state.events[payload.key], 'data', payload.data)
您也可以将其包装到实用程序函数中,该函数使用Vue.set
答案 3 :(得分:-1)
您能尝试一下,让我知道在这两种情况下是否都触发了反应性吗?
首先,删除外部对象的这种不必要的包装,然后将有效负载作为具有所需事件键和该键数据的简单键/值对象发送:
{
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,因为它可以工作,并且会触发与原始类型的反应:
store / index.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
})
main.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)
}
}