Vuex的使用以及持久化的实现(2.0版本)

什么是 vuex ?这里不进行过多介绍,请直接看官网

Vuex 是什么? | Vuex (vuejs.org)

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;
View Code

 

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 }
View Code

 

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>
View Code

 

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 {
    width: 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>
View Code

 

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)

码云地址:vuex-demo · oukele/vueProject - 码云 - 开源中国 (gitee.com)

posted @ 2021-05-29 20:11  追梦滴小蜗牛  阅读(195)  评论(2编辑  收藏  举报