目录

1,前言


最近在重温vue全家桶,再看一遍感觉记忆更深刻,所以专门记录一下。

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

公众号

往期文章

个人主页

超详细!Vuex手把手教程的更多相关文章

  1. 超强、超详细Redis入门教程【转】

    这篇文章主要介绍了超强.超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需要的朋友可以参考下 [本教程目录] 1.redis是什么2.redis的作者何许人也3.谁在使用red ...

  2. 超详细Redis入门教程【转】

    这篇文章主要介绍了超强.超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需要的朋友可以参考下   [本教程目录] 1.redis是什么 2.redis的作者何许人也 3.谁在使 ...

  3. 梦幻西游H5游戏超详细图文架设教程

    前言 想体验经典Q版西游霸服快乐吗?想体验满级VIP的尊贵吗?想体验一招秒杀的爽快吗?各种极品装备.翅膀.宠物通通给你,就在梦幻西游! 本文讲解梦幻西游H5游戏的架设教程,想研究H5游戏如何实现,体验 ...

  4. SCIP | 数学规划求解器SCIP超详细的使用教程

    前言 小伙伴们大家好呀!继上次lp_solve规划求解器的推文出来以后,大家都期待着更多求解器的具体介绍和用法.小编哪敢偷懒,这不,赶在考试周之际,又在忙里偷闲中给大家送上一篇SCIP规划求解的推文教 ...

  5. Mysql学习总结(2)——Mysql超详细Window安装教程

    目录 一.安装包准备 二.开始安装 三.验证安装 四.客户端工具 一.安装包准备 1.下载MySql5.6 http://www.mysql.com/ 下载如下教程,这时要选MySql On Wind ...

  6. iphone 3G\3GS 超详细拆机教程

    更为直观的iphone视频拆机教程: http://bbs.app111.com/thread-243147-1-1.html 第一步: 准备好所需工具 iphone一台....吸盘一个..屏幕布一块 ...

  7. MySQL基础知识(一)-超详细MySQL安装教程

    简介 原计划,今天这篇想要给小伙伴们讲解一下python操作mysql数据库,但是由于近期换了一台新的电脑,所以一看mysql数据库都没安装,所有才有了这篇文章.尽管网上不乏此类型的文章,但是刚好自己 ...

  8. VS Code断点调试PHP超详细萌新教程

    AppServ安装 1. 下载 2. 安装,一路默认设置顺便设置sql密码即可.这里建议不要修改端口,后续教程默认80端口. 3.点我测试,有下图则恭喜你AppServ安装完成. Xdebug配置 1 ...

  9. 秒懂系列,超详细Java枚举教程!!!

    所有知识体系文章,GitHub已收录,欢迎Star!再次感谢,愿你早日进入大厂! GitHub地址: https://github.com/Ziphtracks/JavaLearningmanual ...

随机推荐

  1. 24GHz和77GHz毫米波雷达技术细节

    24GHz和77GHz毫米波雷达技术细节 FMCW Radar Sensitivity Measurement Tech Field Test and Raw Data Analysis Capabi ...

  2. 【NX二次开发】Block UI 截面构建器

    属性说明 属性   类型   描述   常规           BlockID    String    控件ID    Enable    Logical    是否可操作    Group    ...

  3. 空闲时间研究一个小功能:winform桌面程序如何实现动态更换桌面图标

    今天休息在家,由于天气热再加上疫情原因,就在家里呆着,空闲时想着,在很早以前(约3年前),产品人员跟我提了一个需求,那就是winform桌面程序的图标能否根据节日动态更换,这种需求在移动APP上还是比 ...

  4. nacos 实战(史上最全)

    文章很长,而且持续更新,建议收藏起来,慢慢读! 高并发 发烧友社群:疯狂创客圈(总入口) 奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : 极致经典 + 社群大片好评 < Java 高并发 三 ...

  5. 小Z的袜子(hose) &&作业 (莫队)

    莫队:一种非常优雅的暴力,时间复杂度一般情况下是n*根号n,还是很优秀的. 今天水了三道莫队题,对普通莫队有了些了解 1.莫队l和r为指针,维护当前区间的某些信息,一般可以是当前区间不同权值的个数,( ...

  6. Unity3D学习笔记1——绘制一个三角形

    目录 1. 绪论 2. 概述 3. 详论 3.1. 准备 3.2. 实现 3.3. 解析 3.3.1. 场景树对象 3.3.2. 绘制方法 4. 结果 1. 绪论 最近想学习一下Unity3d,无奈发 ...

  7. centos7安装kubernetes1.18.5

    一.设置hosts 修改主机名 [root@localhost kubernetes]# hostnamectl set-hostname master69 四台服务器安装kebernetes,一个m ...

  8. 深入理解 Android ANR 触发原理以及信息收集过程

    一.概述 作为 Android 开发者,相信大家都遇到过 ANR.那么为什么会出现 ANR 呢,ANR 之后系统都做了啥.文章将对这个问题详细解说. ANR(Application Not respo ...

  9. C# 启动项目直接修改电脑的日期格式

    启动界面添加 1.引用添加 using System.Runtime.InteropServices; 2.方法添加 [DllImport("kernel32.dll", Entr ...

  10. .Net Core with 微服务 - Consul 配置中心

    上一次我们介绍了Elastic APM组件.这一次我们继续介绍微服务相关组件配置中心的使用方法.本来打算介绍下携程开源的重型配置中心框架 apollo 但是体系实在是太过于庞大,还是让我爱不起来.因为 ...