zoukankan      html  css  js  c++  java
  • Vue 状态管理 Vuex

    Vue 状态管理 Vuex

    官网文档:https://vuex.vuejs.org/zh/

    Vuex 是一个专门为 Vue.js 应用程序开发的状态管理模式,他采用集中式存储管理应用的所有组件的状态,并且以相应的规则保证状态以一种可以预测的方式发生改变。

    Vuex 的简单理解

    • Vue 应用中的每一个组件在 data() 中封装自己的数据属性,而这些 data 属性是私有的,完全隔离的。
    • 如果我们希望多个组件都能读取到同一个状态数据属性,或者不同的组件的行为需要更新同一状态数据属性,这就需要一个将共享的状态数据属性进行集中式的管理。
    • 这就是 Vuex 状态管理所要解决的问题。

    安装依赖

    npm install --save vuex
    

    在这里插入图片描述

    使用Vuex

    创建文件

    在项目 src 文件夹下创建一个 store 文件夹,存储状态,将所有的状态存储到这个文件夹里面。在 store 文件夹下创建一个 index.js 文件。
    在这里插入图片描述

    创建Vuex对象

    在 index.js 文件中编写 Vuex 对象并导出。

    在状态中存储一个 count 值为 1。

    // 引入 vue 和 vuex
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    // 引入 Vuex 插件
    Vue.use(Vuex)
    
    // 创建一个仓库,用来存储对应的状态
    const store = new Vuex.Store({
        state: { // 存放状态(共享的属性)
            count: 1
        }  
    })
    
    // 导出Vuex对象
    export default store
    

    将 Vuex 注册到 vue实例当中

    在 main.js 文件中注册 Vuex。

    import Vue from "vue";
    import App from "./App.vue";
    import router from "./router";
    // 导入 vuex,默认导入的是 ./store/index.js
    import store from './store'
    
    Vue.config.productionTip = false;
    
    new Vue({
      router,
      store, // 注册
      render: h => h(App)
    }).$mount("#app");
    

    获取状态 count 值

    获取状态值得方式是 $store.state.状态名。

     $store.state.xxx
    

    在组件中使用:

    <template>
      <div class="home">
         count:{{ $store.state.count }}
      </div>
    </template>
    
    <script>
    
    export default {
      name: "Home",
    };
    </script>
    

    在这里插入图片描述

    更改状态值

    1. 在 store 的 mutations 选项中定义方法,才可以改变状态值。
    2. 在通过 $store.commit("mutationName") 触发状态值的改变。

    创建一个修改 count 值得方法,在 index.js 文件中,添加一个增加的方法,修改 state 对象中的 count 值。

    mutations: {
            // 增加的方法,改变state的状态值
            increment(state) {
                state.count ++ 
            }
        }
    

    在这里插入图片描述

    在组件中创建一个按钮,点击按钮,是的状态值 count 自增。

    <template>
      <div class="home">
        <p>count:{{ $store.state.count }}</p>
        <button @click="addCount">count 自加</button>
      </div>
    </template>
    
    <script>
    export default {
      name: "Home",
      methods: {
        addCount() {
          // 现获取状态值
          console.log(this.$store.state.count);
          // 修改 count 值
          this.$store.commit('increment')
        }
      }
    };
    </script>
    

    在这里插入图片描述
    改变状态值 count 的方法就实现了。

    在写一个自减哈,闲着也是闲着,做法和自加是一样的

    index.js文件中:

    mutations: {
            // 增加的方法,改变state的状态值
            increment(state) {
                state.count ++ 
            },
            // 自减
            decrement(state) {
                state.count -- 
            }
        }
    

    组件:

    <template>
      <div class="home">
        <p>count:{{ $store.state.count }}</p>
        <button @click="addCount">count 自加</button>
        <button @click="decrement">count 自减</button>
      </div>
    </template>
    
    <script>
    export default {
      name: "Home",
      methods: {
        addCount() {
          // 现获取状态值
          console.log(this.$store.state.count);
          // 修改 count 值
          this.$store.commit('increment')
        },
        decrement() {
          // 现获取状态值
          console.log(this.$store.state.count);
          // 修改 count 值
          this.$store.commit('decrement')
        }
      }
    };
    </script>
    

    在这里插入图片描述
    任意组件,都可以获取到状态值,数据是共享的,当一个地方改变了状态的值,所有的地方都可以获取到最新状态值。

    提交载荷

    就是向 $store.commit 中提交额外的参数,即 mutation 的载荷 (payload)。

    例如:修改自加功能,增加的时候传进一个参数 n,是 count 加上传进来的 n。修改 index.js 文件自加方法:

    mutations: {
        // 增加的方法,改变state的状态值
        increment(state, n) {  // n 为载荷
            state.count += n   // state.count = state.count + n
        },
        // 自减
        decrement(state) {
            state.count -- 
        }
    }
    

    在这里插入图片描述

    修改组件方法:

    addCount() {
          // 现获取状态值
          console.log(this.$store.state.count);
          // 修改 count 值
          // this.$store.commit('increment')
          this.$store.commit('increment', 10)
    },
    

    在这里插入图片描述
    在这里插入图片描述

    Action的作用和使用

    Action 类似于 mutation,但不同点在于:

    1. Action 提交的是 mutation,而不是在组件中直接变更状态,通过他间接更新 state。
    2. 在组件中通过 this.$store.dispatch('actionName') 触发状态值间的改变。
    3. Action 也支持载荷。
    4. Action 可以包含任意异步操作。

    修改 index.js 文件,添加 actions 。

    // 引入 vue 和 vuex
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    // 引入 Vuex 插件
    Vue.use(Vuex)
    
    // 创建一个仓库,用来存储对应的状态
    const store = new Vuex.Store({
        state: { // 存放状态(共享的属性)
            count: 1
        },
        mutations: {
            // 增加的方法,改变state的状态值
            increment(state, n) {  // n 为载荷
                state.count += n   // state.count = state.count + n
            },
            // 自减
            decrement(state) {
                state.count--
            }
        },
        actions: {
            add(context) {
                // 触发 mutations 中的 increment 来改变 state
                context.commit('increment', 10)
            }
        }
    })
    
    // 导出Vuex对象
    export default store
    

    修改组件,点击自加按钮时候的逻辑:

    addCount() {
          // 现获取状态值
          console.log(this.$store.state.count);
          // 修改 count 值
          // this.$store.commit('increment')
          // this.$store.commit('increment', 10)
          // 触发 action 修改 state
          this.$store.dispatch('add')
       },
    

    在这里插入图片描述
    action 也可以实现载荷

    actions: {
            add(context, n) {
                // 触发 mutations 中的 increment 来改变 state
                context.commit('increment', n)
            }
     }
    
    addCount() {
          // 现获取状态值
          console.log(this.$store.state.count);
          // 修改 count 值
          // this.$store.commit('increment')
          // this.$store.commit('increment', 10)
          // 触发 action 修改 state
          this.$store.dispatch('add', 10)
        },
    

    在这里插入图片描述
    效果一样!

    action 还有其他的提交方式

    比如修改减法

    actions: {
            add(context, n) {
                // 触发 mutations 中的 increment 来改变 state
                context.commit('increment', n)
            },
            // 参数是一个对象,commit就是提交,state就是状态对象,按需传入
            decrement({commit,state}) {
                console.log('actions.decrement.state.count ',state.count)
                commit('decrement')
            }
        }
    

    组件调用减法:

    decrement() {
          // 现获取状态值
          // console.log(this.$store.state.count);
          // 修改 count 值
          // this.$store.commit('decrement')
          this.$store.dispatch('decrement')
    }
    

    派生属性 getter

    1. 有时候哈,我们需要从 store 中的 state 中派生出一些状态。就比如说哈,基于上面的那个代码,增加一个 desc 属性,当那个 count 小于50的时候,desc 的值就是“吃饭饭”,大于等于50小于100,desc 的值就是 “睡觉觉”,当 count 的值大于100,desc 的值就是“打豆豆”。这个时候,我们就需要使用 getter 为我们解决问题了。
    2. getter 其实就是一个类似于计算属性(get)的对象。
    3. 组件中读取 $store.getter.xxx

    修改 index.js 文件,增加 getters 选项:

    getters: { // 定义派生属性
        desc(state) {  // 类似于计算属性的个玩意儿,会监听count值
            // 这个state就是上面的state,他会自动的传进来
            if(state.count < 50){
                return '吃饭'
            } else if (state.count < 100){
                return '睡觉'
            } else {
                return '打豆豆'
            }
        }
    }
    

    在这里插入图片描述
    修改组件,测试派生desc

    <p>派生属性 desc 测试:{{ $store.getters.desc }}</p>
    

    在这里插入图片描述
    效果就是下面的样子啦:
    在这里插入图片描述

    Vuex 模块化 Module 管理

    随着状态值得增加,对状态值操作的增加,index.js 文件会变得越来约大,越来越臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module),每个模块有自己的 state、mutation、action、getter 等。

    结构大体就是下面的样子:

    const moduleA = {
      state: {},
      mutations: {},
      actions: {},
      getters: {}
    }
    
    const moduleB = {
      state: {},
      mutations: {},
      actions: {}
    }
    const store = new Vuex.Store({
      modules:{
        a:modeuleA,
        b:modulesB
      }
    })
    
    store.state.a  // modelA 的状态
    store.state.b  // modelB 的状态
    

    模块化之前代码

    index.js 文件

    // 引入 vue 和 vuex
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    // 引入 Vuex 插件
    Vue.use(Vuex)
    
    // 将 home 相关的状态抽取为一个模块
    const home = {
        state: { // 存放状态(共享的属性)
            count: 1
        },
        mutations: {
            // 增加的方法,改变state的状态值
            increment(state, n) {  // n 为载荷
                state.count += n   // state.count = state.count + n
            },
            // 自减
            decrement(state) {
                state.count--
            }
        },
        actions: {
            add(context, n) {
                // 触发 mutations 中的 increment 来改变 state
                context.commit('increment', n)
            },
            // 参数是一个对象,commit就是提交,state就是状态对象
            decrement({commit,state}) {
                console.log('actions.decrement.state.count ',state.count)
                commit('decrement')
            }
        },
        getters: { // 定义派生属性
            desc(state) {  // 类似于计算属性的个玩意儿,会监听count值
                // 这个state就是上面的state,他会自动的传进来
                if(state.count < 50){
                    return '吃饭'
                } else if (state.count < 100){
                    return '睡觉'
                } else {
                    return '打豆豆'
                }
            }
        }
    }
    
    // 将 goods 相关的状态抽取为一个模块
    const goods = {
        state: {},
        mutations: {},
        actions: {},
        getters: {}
    }
    
    // 创建一个仓库,用来存储对应的状态
    const store = new Vuex.Store({
        modules: {
            home,   // home: home
            goods,
        }
    })
    
    // 导出Vuex对象
    export default store
    

    组件代码

    <template>
      <div class="home">
        <!-- <p>count:{{ $store.state.count }}</p> -->  <!--  模块话之前 -->
        <p>count:{{ $store.state.home.count }}</p>  <!--  模块话之后 -->
        <button @click="addCount">count 自加</button>
        <button @click="decrement">count 自减</button>
        <p>派生属性 desc 测试:{{ $store.getters.desc }}</p>
      </div>
    </template>
    
    <script>
    export default {
      name: "Home",
      methods: {
        addCount() {
          // 现获取状态值
          // console.log(this.$store.state.count);  // 模块化钱前
          console.log(this.$store.state.home.count);  // 模块化后
          // 修改 count 值
          // this.$store.commit('increment')
          // this.$store.commit('increment', 10)
          // 触发 action 修改 state
          this.$store.dispatch('add', 10)
        },
        decrement() {
          // 现获取状态值
          // console.log(this.$store.state.count);
          // 修改 count 值
          // this.$store.commit('decrement')
          this.$store.dispatch('decrement')
        }
      }
    };
    </script>
    

    在这里插入图片描述
    一样的效果!完美~!

    基于 Vuex 标准项目结构重构项目

    如果所有的状态都写在一个 js 中,这个 js 必定会很臃肿,Vuex 并不限制你的代码结构。所以最好把每一部分都单独抽成一个 js 文件。

    Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:

    1. 应用层级的状态应该集中到单个 store 对象中。

    2. 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。

    3. 异步逻辑都应该封装到 action 里面。

    只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。

    对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例:
    在这里插入图片描述

    注意! Vuex 的状态值在所有组件共享,在路由切换的时候状态值会得到保存,但是!在刷新整个页面之后,状态值会重置,这个是后如果想保留状态值,能且只能与 localStorage 进行配合。

    【相关代码:https://gitee.com/wjw1014/vue_learning_vuex

  • 相关阅读:
    SPComm的一点小诀窍 spcomm的问题导致数据丢失 0x11与0x13错误
    关于DELPHI数组,指针,字符串转换的例子!(转)
    SQL常用语法大全
    SQL触发器实例讲解
    Delphi 变体类型(Variant)的介绍(流与变体类型的相互转换、变体类型常用的函数)
    delphi 生成条形码(fastreport 实现)
    delphi 判断字符串有中文
    delphi const
    delphi as
    delphi 字符串常识
  • 原文地址:https://www.cnblogs.com/wjw1014/p/13458389.html
Copyright © 2011-2022 走看看