作用:
统一管理项目状态的,也是一种比较好的组件传递信息的方式;
关键内容:
-
state:
状态数据的储存位置(类似data); -
getters:
可对state中data返回进行加工,并缓存,只有当依赖的data值发生变化时才重新计算,返回计算后的值; 类似计算属性,例如需要将data进行拼接,多个组件都需要使用时; -
mutations:
提交修改state中数据内容的唯一方式,只能是同步代码; 组件中使用方式:this.$store.commit('事件类型'); -
actions:
异步代码,获取到异步数据后,再通过commit提交mutations中的方法,修改更新state数据; 组件中的使用方式:this.$store.dispatch('事件类型'); -
Module:
将store分割成模块(module); 每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块:
实例详情说明:
1.state:
1.1 辅助函数mapState:当需要使用多个state时,使用辅助函数生成多个state的计算属性;
//store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex)
export default new Vuex.Store({
state:{
count:4
}
})
// 组件使用
// 对象形式
computed:mapState({
count: state => state.count, // 返回count,等同于count() {return this.$store.state.count}
countAlias: 'count', // count的别名是countAlias,这时候countAlias等同于count(注意单引号)
sumCount(state) { // 处理多状态:store的数据加上本地的数据
return state.count+this.localCount
}
})
// 数组形式
computed: mapState([
'count' //等同于count:state=>state.count,
])
2.getters:
2.1应用:
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
},
doneTodosCount: (state, getters) => { // 接受第二个参数getter
return getters.doneTodos.length //通过getter访问到doneTodos属性
},
getTodoById: (state) => (id) => { // 让 getter 返回一个函数,来实现给 getter 传参。
return state.todos.find(todo => todo.id === id)
},
}
})
2.2访问:
//访问
store.getters.doneTodos
store.getters.doneTodosCount
store.getters.getTodoById(2) // 返回元素id与传过去的id相等的元素
//组件中使用
computed: {
doneTodosCount () {
return this.$store.getters.doneTodosCount
}
}
2.3辅助函数mapGetters:
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用对象展开运算符,将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'doneTodos',
// ...
])
}
}
3. Mutation:
3.1 应用:
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
//事件类型:increment;回调函数为后面部分;
incrementA (state) {
state.count ++;
},
incrementB (state, n) { // 额外参数载荷(payload)
state.count += n;
},
incrementC (state, payload) { // 大多数情况下,载荷应该是一个对象
state.count += payload.amount
}
}
})
3.2 提交:
// 提交
store.commit('incrementA')
store.commit('incrementB', 6) // 提交载荷
store.commit('incrementC', { amount: 7 })
// 组件中提交
this.$store.commit('事件类型', payload)
3.3 辅助函数 mapMutations:
// 展开store中的mutations方法,以便组件中直接this调用
methods:{
//...
...mapMutations([
'incrementA', //相当于this.$store.commit('increment')
'incrementB', //相当于`this.$store.commit('incrementB', n)`
'incrementC' //相当于this.$store.commit('incrementC', { amount } )
]),
}
4. action:
4.1 应用:
//一个往数组添加随机数的实例:
const store = new Vuex.Store({
state: {
msg: []
},
mutations: {
addMessage(state,msg){
state.msg.push(msg)
}
},
//一个异步操作:
actions: {
getMessages({ context }) { // 可使用 { commit } 直接解析commit出来
// 异步调用接口后,再使用commit提交mutations中的方法修改state数据;
fetch('https://url/api/getnum')
.then(res => res.json())
.then(data => {
context.commit('addMessage',data.data.number)
})
},
async actionA ({ commit }) {
// 获取到接口getDataInfo后,提交到mutations中的gotData中;
commit('gotData', await getDataInfo())
},
async actionB ({ dispatch, commit }) { // 组合
await dispatch('actionA') // 等待 actionA 完成
commit('gotOtherData', await getOtherDataInfo())
}
}
})
4.2 分发:
// 分发
store.dispatch('getMessages');
store.dispatch('事件类型', { amount: 1 }) // 载荷分发
store.dispatch({ type: '事件类型', amount: 1 }) // 对象形式 载荷分发
// 组件中分发
this.$store.dispatch('事件类型')
4.3 辅助函数mapActions:
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'getMessages', // 相当于`this.$store.dispatch('getMessages')`
]),
...mapActions({
addmsg: 'getMessages' //this.addmsg等同于`this.$store.dispatch('getMessages')`
})
}
}
5. module:
5.1 应用:
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
命名空间:
默认情况,模块内部 action、mutation 和 getter 注册在全局命名空间,使得多个模块能对同一 mutation 或 action 作出响应。
模块对象中加入 namespaced: true 使其成为带命名空间的模块,所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名,具有更高的封装度和复用性;
const store = new Vuex.Store({
modules: {
account: {
namespaced: true,
state: () => ({ ... }),
getters: {isAdmin () { ... }}, // 通过 store.getters['account/isAdmin']访问
actions: {login () { ... }}, // 通过 store.dispatch('account/login')分发
mutations: {login () { ... }}, //通过store.commit('account/login')提交
// 模块中嵌套模块 - 继承父模块的命名空间
modules: {
// 模块1 - myPage
myPage: {
state: () => ({ ... }),
getters: {profile () { ... }} // store.getters['account/profile']
},
// 模块2 - mposts - 进一步嵌套命名空间
posts: {
namespaced: true,
state: () => ({ ... }),
getters: {popular () { ... }} // store.getters['account/posts/popular']
}
}
}
}
})
在带命名空间的模块内访问全局内容:
rootState 和 rootGetters 会作为第三和第四参数传入 getter,也会通过 context 对象的属性传入 action。
若需要在全局命名空间内分发 action 或提交 mutation,将 { root: true } 作为第三参数传给 dispatch 或 commit 即可。
modules: {
foo: {
namespaced: true, // 命名空间设置
getters: {
someOtherGetter: state => { ... }
someGetter (state, getters, rootState, rootGetters) { // 1. 对于getter,使用第四个参数 `rootGetters`访问根getter
getters.someOtherGetter // -> 局部的
rootGetters.someOtherGetter // -> 全局的
},
},
actions: {
someOtherAction (ctx, payload) { ... }
someAction ({ dispatch, commit, getters, rootGetters }) { // 2. 对于actions,接受 root 属性来访问根 dispatch 或 commit
dispatch('someOtherAction') // -> 局部的分发
dispatch('someOtherAction', null, { root: true }) // -> 全局的分发
commit('someMutation') // -> 局部的提交
commit('someMutation', null, { root: true }) // -> 全局的提交
},
}
}
}
在带命名空间的模块注册全局 action:
在action中添加 root: true,并将这个 action 的定义放在函数 handler 中。例如:
{
//...
modules: {
foo: {
namespaced: true,
actions: {
someAction: {
root: true,
handler (namespacedContext, payload) { ... } // -> 定义someAction action
}
}
}
}
}
带命名空间的绑定函数:
当使用 mapState, mapGetters, mapActions 和 mapMutations 这些函数来绑定带命名空间的模块时:
普通:
computed: {
...mapState({
a: state => state.some.nested.module.a,
b: state => state.some.nested.module.b
})
},
methods: {
...mapActions([
'some/nested/module/foo', // -> this['some/nested/module/foo']()
'some/nested/module/bar' // -> this['some/nested/module/bar']()
])
}
优化一:
computed: {
...mapState('some/nested/module', {
a: state => state.a,
b: state => state.b
})
},
methods: {
...mapActions('some/nested/module', [
'foo', // -> this.foo()
'bar' // -> this.bar()
])
}
优化二:
import { createNamespacedHelpers } from 'vuex'
const { mapState, mapActions } = createNamespacedHelpers('some/nested/module') // 基于某个命名
export default {
computed: {
...mapState({
a: state => state.a,
b: state => state.b
})
},
methods: {
...mapActions([
'foo',
'bar'
])
}
}