- 1,前言
- 2,Vuex 是什么
- 3,5大属性说明
- 4,state
- 4.1 直接访问
- 4.1 使用mapState映射
- 5,getters
- 5.1 先在vuex中定义getters
- 5.2 直接获取值
- 5.3 使用mapGetters映射
- 6,Mutation
- 6.1,先在mutations中注册事件
- 6.2,在组件中调用方法commit修改值
- 6.3,使用常量定义方法名
- 6.4,使用mapMutations映射
- 7,Action
- 7.1,在store中定义
- 7.2,在组件中使用
- 7.3,使用mapActions映射
- 7.4,简化写法
- 7.5,执行异步操作
- 8,Modules
- 8.1,准备工作
- 8.2,使用modules中注入的模块的state
- 8.3,使用modules中注入模块的getters
- 8.4,使用modules中注入模块的mutations
- 8.5,使用modules中注入模块的actions
- 8.6,命名空间
- 8.6.1,使用
- 8.6.2 ,在带命名空间的模块中内访问全局内容
- 8.6.3,在带命名空间的模块注册全局action
1,前言
最近在重温vue全家桶,再看一遍感觉记忆更深刻,所以专门记录一下(本文vuex版本为v3.x)。
2,Vuex 是什么
Vuex是专为Vue.js开发的状态管理模式。它采用集中式存储,管理所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化(我的理解就是全局变量)。
3,5大属性说明
state
对象类型,类似于实例的 data属性,存放数据
getters
对象类型,类似于实例的计算属性 computed
mutations
对象类型,类似于实例的 methods,但是不能处理异步方法
actions
对象类型,类似于实例的 methods,可以处理异步方法
modules
对象类型,当state内容比较多时,通过该属性分割成小模块,每个模块都拥有自己的 state、mutation、action、getter
4,state
存储在state
中的数据和Vue
实例中的data
遵循相同的规则,必须是纯粹的对象。
4.1 直接访问
this.$store.state.xxx
4.1 使用mapState映射
计数:{{ getCount }}
学校:{{ getSchool('我是参数') }}
5,getters
getter
的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算,并且默认接受state
作为其第一个参数,也可以接受其他getter
作为第二个参数(如下例)
5.1 先在vuex中定义getters
export default new Vuex.Store({
state: {
count: 0,
school: '清华大学'
},
getters: {
// 返回处理后的state值
getValue(state) {
return state.count + '!'
},
// 返回调用自身getters处理后的state值
getGetters(state, getters) {
return state.school + getters.getValue
},
// 接受外部传参后处理的值(在通过方法访问时,每次都会去进行调用,而不会缓存结果)
getParam(state) {
return (param) => {
return state.school + param
}
}
},
mutations: {},
actions: {},
modules: {}
})
5.2 直接获取值
// 取值
console.log(this.$store.getters.getGetters)
// 传参取值
console.log(this.$store.getters.getParam('param'))
5.3 使用mapGetters映射
计数:{{ getGetters }}
学校:{{ getParam(date) }}
6,Mutation
通过调用this.$store.commit('xxx')
,调用mutation
中的方法,更改store
中的值
6.1,先在mutations中注册事件
export default new Vuex.Store({
state: {
count: 0,
school: '清华大学'
},
getters: {},
mutations: {
// 默认state作为第一个参数
handleAdd(state) {
state.count++
},
// 接受传参
handleChange(state, value) {
state.school = value
}
},
actions: {},
modules: {}
})
6.2,在组件中调用方法commit修改值
计数:{{ count }}
增加
传参
6.3,使用常量定义方法名
新建文件mutation-types.js
,定义方法名的常量,并导出
export const ADD_COUNT = 'ADD_COUNT'
export const CHANGE = 'CHANGE'
在store中
import Vue from 'vue'
import Vuex from 'vuex'
import * as MT from './mutation-types'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0,
school: '清华大学'
},
getters: {},
mutations: {
// 默认state作为第一个参数
[MT.ADD_COUNT](state) {
state.count++
},
// 接受传参
[MT.CHANGE](state, value) {
state.school = value
}
},
actions: {},
modules: {}
})
在组件中
计数:{{ count }}
增加
传参
6.4,使用mapMutations映射
计数:{{ count }}
计数:{{ school }}
增加
传参
7,Action
注意,Action
提交的是mutation
,而不是直接变更状态,并且可以包含任意异步操作
7.1,在store中定义
import Vue from 'vue'
import Vuex from 'vuex'
import * as MT from './mutation-types'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0,
school: '清华大学'
},
getters: {},
mutations: {
// 默认state作为第一个参数
[MT.ADD_COUNT](state) {
state.count++
},
// 接受传参
[MT.CHANGE](state, value) {
state.school = value
}
},
actions: {
add(context) {
context.commit(MT.ADD_COUNT)
}
},
modules: {}
})
7.2,在组件中使用
计数:{{ count }}
增加
7.3,使用mapActions映射
import { mapActions } from 'vuex'
methods: {
...mapActions([
'moduleFn'
])
}
或者
import { mapActions } from 'vuex'
methods: {
...mapActions([
fn: 'moduleFn'
])
}
7.4,简化写法
Action
接受一个与store
实例具有相同方法和属性的context
参数对象,因此你可以调用context.commit
提交一个mutation
,或者通过context.state
和context.getters
来获取state
和getters
,利用ES6
的解构,可以简化写法。
actions: {
add({ commit, state }) {
commit(MT.CHANGE, state.school)
}
}
7.5,执行异步操作
在vuex中
import Vue from 'vue'
import Vuex from 'vuex'
import * as MT from './mutation-types'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
getters: {},
mutations: {
// 默认state作为第一个参数
[MT.ADD_COUNT](state) {
state.count++
}
},
actions: {
add({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit(MT.ADD_COUNT)
resolve()
}, 1000)
})
}
},
modules: {}
})
在组件中使用async / await
或者then / catch
处理异步
计数:{{ count }}
增加
8,Modules
当应用变得非常复杂时,store
对象就可能变得相当臃肿。这时候可以将store
分割成模块,每个模块拥有自己的state
、mutation
、action
、getter
、甚至是嵌套子模块,从上至下进行同样方式的分割。
8.1,准备工作
在store目录下新建Modules
文件夹,在Modules
文件夹中新建modulesA.js
,modulesB.js
,如下图
在modulesA.js中写上局部模块的state
、mutation
、action
、getter
,并导出
const moduleA = {
state: () => ({
a: '我是moduleA'
}),
getters: {},
mutations: {},
actions: {}
}
export default moduleA
然后在store
的index.js
中引入,并丢进modules
对象里
import Vue from 'vue'
import Vuex from 'vuex'
import * as MT from './mutation-types'
import moduleA from './modules/moduleA'
import moduleB from './modules/moduleB'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
getters: {},
mutations: {},
actions: {},
modules: {
moduleA,
moduleB
}
})
8.2,使用modules中注入的模块的state
在组件中直接使用
this.$store.state.moduleA.xxx
在组件中使用mapState
映射
{{ moduleA.xxx }}
import { mapState } from 'vuex'
computed: {
...mapState([
'moduleA'
])
}
8.3,使用modules中注入模块的getters
在组件中直接使用
this.$store.getters.getModuleA
在组件中使用mapState
映射
{{ getModuleA }}
import { mapGetters } from 'vuex'
computed: {
...mapGetters([
'getModuleA'
])
}
模块内部的getter
,接受的参数state
和getters
是模块的局部状态对象,而根节点的状态会作为第三个参数rootState
暴露出来
const moduleA = {
getters: {
getModuleA(state, getters, rootState) {
return state.xxx + '---' + rootState.xxx
}
}
}
如果需要带参数
const moduleA = {
getters: {
getModuleA(state, getters, rootState) {
return (value) => {
return state.a + '---' + value
}
}
}
}
8.4,使用modules中注入模块的mutations
在组件中直接使用
this.$store.commit('setModuleA') || this.$store.commit('setModuleA', '参数')
在组件中使用mapMutations
映射
import { mapMutations } from 'vuex'
methods: {
...mapMutations([
openFn: 'setModuleA'
])
}
模块内部的mutations
,默认接受的第一个参数state
是模块的局部状态对象
const moduleA = {
mutations: {
setModuleA(state) {
state.xxx += 'xxx'
}
}
}
如果需要带参数
const moduleA = {
mutations: {
setModuleA(state, value) {
state.xxx += value
}
}
}
8.5,使用modules中注入模块的actions
在组件中直接使用
this.$store.dispatch('xxx')
在组件中使用mapActions
映射
import { mapActions } from 'vuex'
methods: {
...mapActions([
'moduleA'
])
}
或者重命名
import { mapActions } from 'vuex'
methods: {
...mapActions({
fn: 'moduleA'
})
}
对于模块内部的action
,局部状态通过context.state
暴露出来,根节点状态则为context.rootState
const moduleA = {
// ...
actions: {
fn ({ state, commit, rootState }) {
if ((state.count + rootState.count) % 2 === 1) {
commit('increment')
}
}
}
}
8.6,命名空间
默认情况下,模块内部的action
、mutation
和getter
是注册在全局命名空间的,这样使得多个模块能够对同一mutation
或action
作出响应。如果希望模块具有更高的封装度和复用性,可以通过给模块添加namespaced: true
的方式使其成为带命名空间的模块。当模块被注册后,它的所有getter
、action
及mutation
都会自动根据模块注册的路径调整命名。
8.6.1,使用
先在模块moduleB.js
中添加namespaced: true
const moduleB = {
namespaced: true,
state: () => ({
b: '我是moduleB'
}),
mutations: {},
actions: {},
getters: {}
}
export default moduleB
在store
的index.js
中
import moduleA from './modules/moduleA'
import moduleB from './modules/moduleB'
export default new Vuex.Store({
state: {},
getters: {},
mutations: {},
actions: {},
modules: {
moduleA,
moduleB
}
})
如果在组件中使用命名空间,需要带上空间名称,mapState
, mapGetters
, mapMutations
,mapActions
用法一样。
8.6.2 ,在带命名空间的模块中内访问全局内容
如果你希望使用全局的state
和getter
,rootState
和rootGetters
会作为第三和第四参数传入getter
,也会通过context
对象的属性传入action
。若需要在全局命名空间内分发action
或提交mutation
,将{ root: true }
作为第三参数传给dispatch
或commit
即可
const moduleA = {
namespaced: true,
state: () => ({
a: '我是moduleA'
}),
getters: {
getModuleA(state, getters, rootState, rootGetters) {
// 使用全局命名空间的state或getters
return state.a + rootState.count
}
},
mutations: {
setModuleA(state) {
console.log(state.a)
}
},
actions: {
addM({ state, commit, dispatch, rootState, rootGetters }) {
console.log(rootState)
console.log(rootGetters)
// 调用全局命名空间的方法
dispatch('rootFunction', null, { root: true })
}
}
}
export default moduleA
8.6.3,在带命名空间的模块注册全局action
在带命名空间的模块注册全局action
,需要添加root: true
,并将这个action
的定义放在函数handler
中,其中,handler的第一个参数namespacedContext
就是action
中的Context
参数
const moduleA = {
namespaced: true,
state: () => ({
a: '我是moduleA'
}),
getters: {},
mutations: {},
actions: {
rootFn: {
root: true,
handler(namespacedContext, param) {
console.log(namespacedContext.state)
}
}
}
}
export default moduleA
如果看了觉得有帮助的,我是@鹏多多,欢迎 点赞 关注 评论;END
公众号
往期文章
- 使用nvm管理node.js版本以及更换npm淘宝镜像源
- 细数JS中实用且强大的操作符&运算符
- vue中利用.env文件存储全局环境变量,以及配置vue启动和打包命令
- 微信小程序实现搜索关键词高亮
个人主页
- CSDN
- GitHub
- 简书
- 博客园
- 掘金