Vuex
Vuex 是什么?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
—— Vuex 官方文档
在构建 Vue 单页面应用时,Vuex 为我们提供了全局状态管理。在 state 中定义的数据后,你可以在项目中任一个组件中进行获取或修改,并且你的修改可以得到全局的相应变更。当我们想要在项目中定义和使用全局变量时,使用 Vuex 是一个很好的解决方法。
- state:对数据的全局存储
- getter:和 Vue计算属性 computed 一样,来实时监听 state 值的变化 (最新状态)
- mutations:对数据的同步更改
- actions:对数据的异步更改
安装和引入
在你的 Vue 项目中安装 Vuex
npm install vuex --save
在 src
文件夹下创建一个 vuex
文件夹,并在 src/vuex
文件夹里新建一个 store.js
,内容如下:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store()
export default store
在 main.js
中,通过在根实例中注册 store
选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store
访问到。
import store from './vuex/store'
new Vue({
el: '#app',
router,
store, // 使用store
render: h => h(App)
})
开始
在本示例中,我们要在 Vuex 中定义一个全局变量 isCollapse
。在任一组件中,点击 展开/收起 按钮,将会将 isCollapse
变量取反,在项目中各个组件都根据这个变量来判断侧栏 (Side bar) 是否收起。为了说明参数传递的方法,下面还添加了 name
和 num
两个全局变量。
state
设置一个全局访问的 state
对象,并把它放到 store
里面
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 储存全局变量
const state = {
// 要使用的全局变量初始值
isCollapse: false,
name: 'no one',
num: 1
}
const store = new Vuex.Store({
state
})
export default store
现在,在任一个组件中,通过 this.$store.state.isCollapse
,this.$store.state.name
等,已经可以获取到这些全局变量了,但这并不是理想的方式,Vuex 提供了 getters,Vuex 允许我们在 store 中定义 “getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
getters
定义 getters
,并把它放到 store
里面
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 储存全局变量
const state = {
// 要使用的全局变量初始值
isCollapse: false,
name: 'no one',
num: 1
}
// 获取state中实时更新的值
const getters = {
getIsCollapse (state) {
return state.isCollapse
},
getName (state) {
return state.name
},
getNum (state) {
return state.num
}
}
const store = new Vuex.Store({
state,
getters
})
export default store
现在,在任一组件中,使用如 this.$store.getters.getIsCollapse
就可以获取到这些变量。但是,我们通常还需要对全局变量进行更改,这就要用到 mutations 对象。
mutations
更改 Vuex 的 store
中的状态的唯一方法是提交 mutation。如下定义好 mutations
,并把它放进 store
里面。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 储存全局变量
const state = {
// 要使用的全局变量初始值
isCollapse: false,
name: 'no one',
num: 1
}
// 获取state中实时更新的值
const getters = {
getIsCollapse (state) {
return state.isCollapse
},
getName (state) {
return state.name
},
getNum (state) {
return state.num
}
}
// mutations: 对数据的同步更改
const mutations = {
mutationsIsCollapse (state) {
state.isCollapse = !state.isCollapse
},
mutationsName (state, payload) {
state.name = payload.value
},
mutationsNum (state, payload) {
state.num += payload.value
}
}
const store = new Vuex.Store({
state,
getters,
mutations
})
export default store
现在你可以使用 this.$store.commit
方法来修改 store 的数据:
this.$store.commit('mutationsIsCollapse')
注意到你可以向 store.commit
传入额外的参数,即 mutation 的 载荷(payload)。比如你要修改 num
,你可以直接传递一个数字,但我们通常不会这么做,大多数情况下,payload
应该是一个对象:
this.$store.commit('mutationsIsCollapse', {
key: 'num',
value: 5
})
注意:对于 mutations
以及接下来的 action
,你向他们传递的额外参数只能有一个,如果传递两个或多个额外参数,那么除了第一个参数,其他都将变成 undefined
。因此,如果你要传递对个参数,请把他们放进 payload
里。
现在我们可以通过 mutations
来修改数据了,但要记住 mutations
里面的函数都是同步函数。按照官方文档对这里的解释是:
现在想象,我们正在 debug 一个 app 并且观察 devtool 中的 mutation 日志。每一条 mutation 被记录,devtools 都需要捕捉到前一状态和后一状态的快照。然而,在上面的例子中 mutation 中的异步函数中的回调让这不可能完成:因为当 mutation 触发的时候,回调函数还没有被调用,devtools 不知道什么时候回调函数实际上被调用——实质上任何在回调函数中进行的状态的改变都是不可追踪的。
因此这不是理想的改变数据的方法,我们要使用 actions
对数据进行异步修改
actions
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
让我们定义 actions
对象并把它放进 store
里:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 储存全局变量
const state = {
// 要使用的全局变量初始值
isCollapse: false,
name: 'no one',
num: 1
}
// 获取state中实时更新的值
const getters = {
getIsCollapse (state) {
return state.isCollapse
},
getName (state) {
return state.name
},
getNum (state) {
return state.num
}
}
// mutations: 对数据的同步更改
const mutations = {
mutationsIsCollapse (state) {
state.isCollapse = !state.isCollapse
},
mutationsName (state, payload) {
state.name = payload.value
},
mutationsNum (state, payload) {
state.num += payload.value
}
}
// actions: 对数据的异步更改
const actions = {
changeIsCollapse (context) {
context.commit('mutationsIsCollapse')
},
setName (context, payload) {
context.commit('mutationsName', payload)
},
setNum (context, payload) {
context.commit('mutationsNum', payload)
}
}
const store = new Vuex.Store({
state,
getters,
mutations,
actions
})
export default store
actions
通过this.$store.dispatch
方法触发:
this.$store.dispatch('changeIsCollapse')
this.$store.dispatch('setName', {
key: 'name',
value: 'someone'
})
this.$store.dispatch('setNum', {
key: 'num',
value: 5
})
这样就可以对全局数据进行更改了。记住,我们不要使用 mutations
对数据进行更改,而是要使用 actions
。这样一来,修改全局数据后,在项目的任意组件中都可以使用 getters
来获取全局数据最新的值。