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映射
<template> <div id="communication"> <p>计数:{{ getCount }}</p> <p>学校:{{ getSchool('我是参数') }}</p> </div></template><script>import { mapState } from 'vuex'export default { name: 'Vuex', data() { return { date: 1998 } }, computed: { ...mapState({ // mapState默认会把state当第一个参数传进来 getCount: state => state.count, getSchool(state) { return (val) => { return state.school + val + this.date } } }) }, mounted() { // 间接取值 console.log(this.$store.state.count) }}</script>
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映射
<template> <div id="communication"> <p>计数:{{ getGetters }}</p> <p>学校:{{ getParam(date) }}</p> </div></template><script>import { mapGetters } from 'vuex'export default { name: 'Vuex', data() { return { date: 1998 } }, computed: { ...mapGetters([ 'getGetters', 'getParam' ]) }, mounted() { // 间接取值 console.log(this.$store.getters.getGetters) console.log(this.getParam(this.date)) }}</script>
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批改值
<template> <div id="communication"> <p>计数:{{ count }}</p> <el-button @click="handleStoreAdd">减少</el-button> <el-button @click="handleStoreChange">传参</el-button> </div></template><script>import { mapState } from 'vuex'export default { name: 'Vuex', data() { return { school: '武汉大学' } }, computed: { ...mapState([ 'count' ]) }, methods: { // 调用批改 handleStoreAdd() { this.$store.commit('handleAdd') }, // 传递参数批改 handleStoreChange() { this.$store.commit('handleChange', this.school) } }}</script>
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: {}})
在组件中
<template> <div id="communication"> <p>计数:{{ count }}</p> <el-button @click="handleStoreAdd">减少</el-button> <el-button @click="handleStoreChange">传参</el-button> </div></template><script>import { mapState } from 'vuex'import * as MT from '../../store/mutation-types'export default { name: 'Vuex', data() { return { school: '武汉大学' } }, computed: { ...mapState([ 'count' ]) }, methods: { // 调用批改 handleStoreAdd() { this.$store.commit(MT.ADD_COUNT) }, // 传递参数批改 handleStoreChange() { this.$store.commit(MT.CHANGE, this.school) } }}</script>
6.4,应用mapMutations映射
<template> <div id="communication"> <p>计数:{{ count }}</p> <p>计数:{{ school }}</p> <el-button @click="handleStoreAdd">减少</el-button> <el-button @click="handleStoreChange(schools)">传参</el-button> </div></template><script>import { mapState, mapMutations } from 'vuex'import * as MT from '../../store/mutation-types'export default { name: 'Vuex', data() { return { schools: '武汉大学' } }, computed: { ...mapState([ 'count', 'school' ]) }, methods: { ...mapMutations({ handleStoreAdd: MT.ADD_COUNT, handleStoreChange: MT.CHANGE }) }}</script>
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,在组件中应用
<template> <div id="communication"> <p>计数:{{ count }}</p> <el-button @click="actionAdd">减少</el-button> </div></template><script>import { mapState, mapMutations } from 'vuex'import * as MT from '../../store/mutation-types'export default { name: 'Vuex', data() { return { schools: '武汉大学' } }, computed: { ...mapState([ 'count', 'school' ]) }, methods: { ...mapMutations({ handleStoreAdd: MT.ADD_COUNT, handleStoreChange: MT.CHANGE }), // 调用action的办法,须要应用$store.dispatch actionAdd() { this.$store.dispatch('add') } }}</script>
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
解决异步
<template> <div id="communication"> <p>计数:{{ count }}</p> <el-button @click="actionAdd">减少</el-button> </div></template><script>import { mapState, mapMutations } from 'vuex'import * as MT from '../../store/mutation-types'export default { name: 'Vuex', data() { return { schools: '武汉大学' } }, computed: { ...mapState([ 'count', 'school' ]) }, methods: { ...mapMutations({ handleStoreAdd: MT.ADD_COUNT, handleStoreChange: MT.CHANGE }), // 调用action的办法,须要应用$store.dispatch async actionAdd() { await this.$store.dispatch('add') console.log(1998) } }}</script>
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
映射
<span>{{ moduleA.xxx }}</span>import { mapState } from 'vuex'computed: { ...mapState([ 'moduleA' ])}
8.3,应用modules中注入模块的getters
在组件中间接应用
this.$store.getters.getModuleA
在组件中应用mapState
映射
<p>{{ getModuleA }}</p>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
用法一样。
<script>import { mapState, mapGetters, mapMutations } from 'vuex'export default { name: 'Vuex', data() { return {} }, computed: { // 此处注入的是moduleA模块的数据 ...mapState('moduleA', [ 'a' ]), // 须要注入moduleB模块,就再写一个 ...mapState('moduleB', [ 'b' ]) }, mounted() { // 间接应用 console.log(this.$store.state.moduleA.a) console.log(this.$store.state.moduleB.b) }, methods: {}}</script>
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淘宝镜像源
个人主页
- CSDN
- GitHub
- 简书
- 博客园
- 掘金