zoukankan      html  css  js  c++  java
  • 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 {
         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)

  • 相关阅读:
    ElasticSearch学习记录
    用java代码手动控制kafkaconsumer偏移量
    kafka0.9.0及0.10.0配置属性
    kafka常用命令
    kafka消费者客户端(0.9.0.1API)
    kafka入门教程链接
    编程内功
    bzoj3145:[Feyat cup 1.5]Str
    3 SpringBoot与微服务
    2 微服务存在的问题和解决方案
  • 原文地址:https://www.cnblogs.com/oukele/p/14826248.html
Copyright © 2011-2022 走看看