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.statecontext.getters来获取stategetters,利用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宰割成模块,每个模块领有本人的statemutationactiongetter、甚至是嵌套子模块,从上至下进行同样形式的宰割。

8.1,筹备工作

在store目录下新建Modules文件夹,在Modules文件夹中新建modulesA.jsmodulesB.js,如下图

在modulesA.js中写上部分模块的statemutationactiongetter,并导出

const moduleA = {    state: () => ({        a: '我是moduleA'    }),    getters: {},    mutations: {},    actions: {}}export default moduleA

而后在storeindex.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,承受的参数stategetters是模块的部分状态对象,而根节点的状态会作为第三个参数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,命名空间

默认状况下,模块外部的actionmutationgetter是注册在全局命名空间的,这样使得多个模块可能对同一mutationaction作出响应。如果心愿模块具备更高的封装度和复用性,能够通过给模块增加namespaced: true的形式使其成为带命名空间的模块。当模块被注册后,它的所有getteractionmutation都会主动依据模块注册的门路调整命名。

8.6.1,应用

先在模块moduleB.js中增加namespaced: true

const moduleB = {    namespaced: true,    state: () => ({        b: '我是moduleB'    }),    mutations: {},    actions: {},    getters: {}}export default moduleB

storeindex.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, mapMutationsmapActions用法一样。

<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 ,在带命名空间的模块中内拜访全局内容

如果你心愿应用全局的stategetterrootStaterootGetters会作为第三和第四参数传入getter,也会通过context对象的属性传入action。若须要在全局命名空间内散发action或提交mutation,将{ root: true }作为第三参数传给dispatchcommit即可

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
  • 简书
  • 博客园
  • 掘金