什么是 vuex ?这里不进行过多介绍,请直接看官网
Vuex 主要有四部分:
1. state: 包含了 store 中存储的各个状态。
2. getter:类似于 Vue 中的计算属性,根据其他 getter 或 state 计算返回值。
3. mutation:一组方法,是改变store中状态的执行者,只能是同步操作。
4. action:一组方法,其中可以包含异步操作。
源码代码在 文章的最下方(注意: 首次运行本项目时,请先输入命令: npm install ,进行安装对应的模块依赖)
1、假设你的项目已经建好,并且也已经安装了 Vuex ....
2、在 src 目录中 新增一个名为 store 的文件夹,我的项目结构如下:

3、在 store 文件夹中 新增 index.js 文件
内容如下 ( require.context('./modules') 这个 modules 怎么来的 在 第4个步骤 有说明 )

import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) // 批量自动导入 自定义不同的vuex模块 let modules = {} // 在 modules当前目录中 找出所有以 .js 结尾的文件 const files = require.context('./modules', false, /.js$/); files.keys().forEach(key => { modules[key.replace(/(./|.js)/g, "")] = files(key).default; }) Object.keys(modules).forEach((key) => { // 使其成为带命名空间的模块。 // 保证在变量名一样的时候,添加一个父级名拼接 modules[key]["namespaced"] = true; }); // 以下的结果为: /** * * { * "storeDemo1": { 第一个模块 * "namespaced": true, * "state": { * "aFlag": false * }, * }, * "storeDemoN.." : { 第 n 个 模块 * "namespaced": true, * "state": { * "N..Flag": false * }, * } * } */ const store = new Vuex.Store({ modules }) export default store;
4、在 store 文件夹中 新增 modules 文件夹,然后再 modules 文件夹 新建一个 storeDemo1.js 文件

storeDemo1.js 内容如下

/** * 数据源 */ const state = { aFlag: false, msg: 'oukele', } /** * 在mutations中写上自定义的方法, * 然后在组件的js中通过 this.$store.commit("自定义的方法名") * 可以更新 store(即上方定义的 state对象 的属性值) 中的数据和状态 * * 注意:mutations 必须是同步函数 ( 因为在 mutations 中导致任何数据源状态变更都应该在此刻完成 ) * 官方解释:在 mutation 中混合异步调用会导致你的程序很难调试。 * 例如,当你调用了两个包含异步回调的 mutation 来改变状态, * 你怎么知道什么时候回调和哪个先回调呢?这就是为什么我们要区分这两个概念。 * 在 Vuex 中,mutation 都是同步事务 * * 为了处理异步操作,请使用 Action */ const mutations = { /** * 更改 state 中 aFlag 的值 方法 * @param state 数据源对象 */ changeAFlag(state){ state.aFlag = true; }, /** * 更改 state 中 msg 的值 方法( 可以传递自定义参数 ) + 本地持久化 * @param state 数据源对象 * @param params 传递的自定义参数 * @param isEndurance 是否本地持久化 */ changeMsg(state , params , isEndurance){ // DOTO // 等会再完善 console.log( state , params + " - " + isEndurance ) } } /** * store 中定义“getter”(可以认为是 store 的计算属性) * Getter 会暴露为 store.getters 对象,你可以以属性的形式访问 state(数据源中的) 这些值 */ const getters = { /** * 在外部中 可通过 this.$store.getters.getAFlag 取出 aFlag 的值 * 注意:因为我这里使用了 模块化,所以使用时应该是这样的调用: * 模块名 + 调用的函数 * this.$store.getters['storeDemo1/getAFlag'] * * @param state */ getAFlag(state){ return state.aFlag; }, msg( state ){ return state.msg; } } export default { state , mutations , getters }
5、上面的 步骤 都是为 Vue实例提供创建好的store ,因此使用时,需在 main.js 进行 注入该 store
6、因为我是使用 vue/cli 创建的项目,创建出来的项目有一个简单的示例,我这边去除部分冗余代码
App.vue 内容如下

<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Hello World"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
HelloWorld.vue 内容如下

<template>
<div class="hello">
<h1>{{ msg }}</h1>
<div class="demo-body">
<div class="showText">
<div>
aFlag:{{ aFlag2 }}
</div>
<div>
msg: {{ vuexMsg }}
</div>
</div>
<div class="operating">
<button @click="changeAFlag">
操作 aFlag
</button>
<button @click="changeMsg(false)">
操作 msg
</button>
<button @click="changeMsg(true)">
操作 msg + 持久化
</button>
</div>
</div>
</div>
</template>
<script>
import {mapState , mapGetters} from "vuex";
export default {
name: 'HelloWorld',
props: {
msg: String
},
computed: {
// 获取 vuex 的值 有以下几种方式
// 1.
aFlag0(){
return this.$store.getters['storeDemo1/getAFlag'];
},
// 2. 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters("storeDemo1",{
aFlag1: 'getAFlag'
}),
// 也可以这样
...mapGetters({
aFlag2: 'storeDemo1/getAFlag',
vuexMsg: 'storeDemo1/msg',
// 取出 某个 模块中的 getAFlag 函数返回的值,并且映射到 nFlag 上
// nFlag: 'xxx/getAFlag',
}),
// 3.
...mapState("storeDemo1",{
aFlag3:state => state.aFlag
}),
},
methods: {
/**
* 修改存在 vuex 中的aFlag值
*/
changeAFlag(){
this.$store.commit('storeDemo1/changeAFlag');
},
changeMsg(isEndurance){
console.log(isEndurance)
this.$store.commit('storeDemo1/changeMsg');
}
}
}
</script>
<style scoped>
.demo-body {
30%;
margin: auto;
display: flex;
flex-direction: column;
}
.demo-body .showText {
background-color: blanchedalmond;
padding-top: 10px;
height: 150px;
}
.demo-body .operating {
padding: 10px 0 10px 0;
background-color: gray;
}
</style>
7、将项目运行起来效果如下

8、当点击 操作aFlag 按钮时,会将 aFlag的值修改成 true

操作aFlag 按钮 绑定上了
changeAFlag 函数

changeAFlag 函数内容如下 ( 注意:mutations 中的方法,要使用 store.commit 方法来触发 )
为什么是 this.$store.commit('storeDemo1/chageAFlag') ,而不是 this.$store.commit('chageAFlag')?
因为 我们这个项目 是将 store 分割成 模块,每个模块拥有自已的 state,mutation,action,getter
直接 使用 this.$store.commit('chageAFlag') ,浏览器会提示:它不知道你要执行哪一个模块的 chageAFlag 的方法

storeDemo1 模块中 的 changeAFlag 方法

aFlag的值 由 false 变成 true ,说明 我们将 vuex 中的 数据修改成功了。
但是 由于 vuex的数据 是存在内存中的,只要一经过刷新,所有的数据都会丢失,有时候有些数据我们并不想那么轻易让它就这丢失了,比如 用户的token
所以 下面的步骤 将采取 vuex + localStore 的方式实现 vuex的持久化效果
9、实现 vuex 的持久化效果
完善 storeDemo1.js 中 mutations 的 chageMsg 方法代码
注意:我这里 的 isEndurance 是无法获取外部传递过来的值(
....尴尬了..)

官方解释:


完善的内容如下:

完善 storeDemo1.js 中 getter 的 msg 方法代码

完善 HelloWorld.vue 中 操作 msg 和 操作 msg + 持久化 按钮 触发事件


测试效果如下:

10、Vuex 的 action 使用
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
在 HelloWorld.vue 新增一个按钮 + 对应的事件 + 新增一个显示的状态
新增一个显示的状态


按钮的事件

storeDemo1.js 新增 actions 组方法


效果如下:

GitHub地址:vueProject/vuex-demo at main · oukele/vueProject (github.com)
