• Vue--vuex的使用


    Vuex 概述

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

    • Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
    • Vue 应用中的每个组件在 data() 中封装着自己数据属性,而这些 data 属性都是私有的,完全隔离的。
    • 如果我们希望多个组件都能读取到同一状态数据属性,或者不同组件的行为需要更新同一状态数据属性,
    • 这就需要一个将共享的状态数据属性进行集中式的管理。
    • 这就是 Vuex 状态管理所要解决的问题。

    简单使用

    使用vue-cli创建一个项目,命名为vue-demo,安装依赖和运行

    # 进入工程目录
    cd vuex-demo
    # 安装依赖 npm install --save vuex
    # 运行项目 npm run serve

    访问 http://localhost:8080/,正常访问就表示配置的没有问题

    每一个 Vuex 项目的核心就是 store(仓库)。 store 就是一个对象,它包含着你的项目中大部分的状态(state)。

    state 是  store 对象中的一个选项,是 Vuex 管理的状态对象(共享的数据属性)

    在 src 目录下创建 store 目录,store 下创建 index.js 文件, 编码如下:

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    // 引用vuex插件
    Vue.use(Vuex)
    
    const  store = new Vuex.Store({ //注意V和S都是大写
        // 存放状态(共享属性)
        state:{
            count: 1
        }
    })
    
    
    export default store

    修改 main.js,导入和注册 store,编码如下:

    import Vue from "vue";
    import App from "./App.vue";
    import router from "./router";
    
    import store from './store'
    
    Vue.config.productionTip = false;
    
    new Vue({
      router,
      store, // 注册
      render: h => h(App)
    }).$mount("#app");

    组件中读取 state 状态数据,修改 srcviewsHome.vue,编码如下:

    <template>
     <div>
     count: {{ $store.state.count }}
     </div>
    </template>
    <script>
    </script>

    访问 http://localhost:8080/ 页面显示如下

     改变状态值 mutation

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

    修改 store/index.js , 在 store 中添加 mutations 选项,编码如下:

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    // 引用vuex插件
    Vue.use(Vuex)
    
    const  store = new Vuex.Store({ //注意V和S都是大写
        // 存放状态(共享属性)
        state:{
            count: 1
        },
    
        // 改变state状态
        mutations:{
            // 加法
            increment(state){
                state.count++
            },
            // 减法
            decrement(state){
                state.count--
            }
        }
    })
    
    
    export default store

    修改 srcviewsHome.vue ,调用 mutations 中 increment、decrement 方法

    <template>
     <div>
     count: {{ $store.state.count }}
     <button @click="addCount">加法</button>
     <button @click="decrement">减法</button>
     </div>
    </template>
    <script>
    export default{
        methods: {
      addCount() {
       // 获取状态值
       console.log(this.$store.state.count)
       // 通过commit 调用 mutations 中的 increment 改变状态值
       this.$store.commit('increment')
     },
      decrement() {
        console.log(this.$store.state.count)
       // 通过commit 调用 mutations 中的 decrement 改变状态值
       this.$store.commit('decrement')
     }
    },
    }
    </script>

    点击  加法 按钮,控制台和页面显示数字变化

    载荷

    你可以向  $store.commit 传入额外的参数,即 mutation 的 载荷(payload):

    修改 srcstore 下的 index.js

    ......
        // 改变state状态
        mutations:{
            increment(state, n){  // n 为载荷
                state.count+=n // state.count=state.count+n
            },
            decrement(state){
                state.count--
            }
        }
    })

    修改 viewsHome.vue 组件

    <template>
     <div>
     count: {{ $store.state.count }}
     <button @click="addCount">加法</button>
     <button @click="decrement">减法</button>
     </div>
    </template>
    <script>
    export default{
        methods: {
      addCount() {
       // 获取状态值
       console.log(this.$store.state.count)
       // 通过commit 调用 mutations 中的 increment 改变状态值
       this.$store.commit('increment',5) // 提交载荷
     },
      decrement() {
        console.log(this.$store.state.count)
       // 通过commit 调用 mutations 中的 decrement 改变状态值
       this.$store.commit('decrement')
     }
    },
    }
    </script>

    页面上点击加法会一次加5,减法还是一个一个的减

    Action

    Action 类似于 mutation,不同在于:

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

    修改 store/index.js ,增加 actions 选项

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    // 引用vuex插件
    Vue.use(Vuex)
    
    const  store = new Vuex.Store({ //注意V和S都是大写
        // 存放状态(共享属性)
        state:{
            count: 1
        },
    
        // 改变state状态
        mutations:{
            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)
               },
                decrement({commit, state}) { // 按需传值
                  commit('decrement')
               }
             }
    })
    
    
    export default store

    修改 viewsHome.vue, 触发 action 改变值

    <template>
     <div>
     count: {{ $store.state.count }}
     <button @click="addCount">加法</button>
     <button @click="decrement">减法</button>
     </div>
    </template>
    <script>
    export default{
        methods: {
      addCount() {
            // 获取状态值
           console.log(this.$store.state.count)
           // 通过commit 调用 mutations 中的 increment 改变状态值
           // this.$store.commit('increment')
           // this.$store.commit('increment', 10) // 提交载荷
           // 触发 actions 中的 add 改变状态值
           this.$store.dispatch('add', 10)
     },
      decrement() {
        console.log(this.$store.state.count)
       // 通过commit 调用 mutations 中的 decrement 改变状态值
        //    this.$store.commit('decrement')
         this.$store.dispatch('decrement')
     }
    },
    }
    </script>

    派生属性 getter

    有时候我们需要从 store 中的 state 中派生出一些状态。

    例如:基于上面代码,增加一个 desc 属性,当 count 值小于 50,则 desc 值为 吃饭 ; 大于等于 50 小于100,则desc 值为 睡觉 ; 大于100 , 则 desc 值为 打豆豆 。这时我们就需要用到 getter 为我们解决。

    getter 其实就类似于计算属性(get)的对象

    组件中读取 $store.getters.xxx

    修改 storeindex.js ,增加 getters 选项

    getters 中接受 state 作为其第一个参数,也可以接受其他 getter 作为第二个参数

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    // 引用vuex插件
    Vue.use(Vuex)
    
    const  store = new Vuex.Store({ //注意V和S都是大写
        // 存放状态(共享属性)
        state:{
            count: 1
        },
    
        // 改变state状态
        mutations:{
            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)
               },
                decrement({commit, state}) { // 按需传值
                  commit('decrement')
               }
             },
        //派生属性
          getters: {
                desc(state) {
                  if(state.count < 50) {
                    return '吃饭'
                 }else if(state.count < 100) {
                    return '睡觉'
                 }else {
                    return '打豆豆'
                 }
                    }
                }
    })
    
    
    export default store

     修改 viewsHome.vue, 显示派生属性的值

    <template>
     <div>
     count: {{ $store.state.count }}
     <button @click="addCount">加法</button>
     <button @click="decrement">减法</button>
        派生属性desc: {{ $store.getters.desc }}
     </div>
    </template>

    点击 Home 页面的  触发改变 按钮,当 count 新增到  51 , desc 是否会显示为  睡觉

     Module

    由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,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: moduleA,
      b: moduleB
    }
    })
    store.state.a // -> moduleA 的状态
    store.state.b // -> moduleB 的状态

    修改 storeindex.js

    import Vue from 'vue'
    import Vuex from 'vuex'
    // 引入 Vuex 插件
    Vue.use(Vuex)
    
    const home = {
      // 存放状态(共享属性)
      state: {
        count: 1
     },
      //派生属性
      getters: {
        desc(state) {
          if(state.count < 50) {
            return '吃饭'
         }else if(state.count < 100) {
            return '睡觉'
         }else {
            return '打豆豆'
         }
       }
     },
      // 改变 state 状态
      mutations: {
        increment(state, n) { // n 为载荷
          // state.count ++
          state.count += n
       },
        decrement(state) {
          state.count --
       }
     },
      actions: {
        add(context) {
          // 触发 mutations 中的 increment 改变 state
          context.commit('increment', 10)
       },
        decrement({commit, state}) { // 按需传值
          commit('decrement')
       }
     }
    }
    
    const store = new Vuex.Store({ // 注意V 和 S都是大写字母
      modules: {
        home // home: home
     }
    })
    export default store

    修改 Home.vue

    <template>
     <div>
       <!--修改部分-->
     count: {{ $store.state.home.count }}
      <button @click="addCount">加法</button>
      <button @click="decrement">减法</button>
     派生属性desc: {{ $store.getters.desc }}
     </div>
    </template>
     
    <script>
    export default {
     methods: {
      addCount() {
       console.log(this.$store.state.home.count)
       this.$store.dispatch('add', 10)
     },
      decrement(){
       this.$store.dispatch('decrement')
     }
    },
    }
    </script>

    标准项目结构

    如果所有的状态都写在一个 js 中,这个 js 必定会很臃肿,Vuex 并不限制你的代码结构。但是它建议你按以下代码
    结构来构建项目结构:

    ├── index.html
    ├── main.js
    ├── api
    │  └── ... # 抽取出API请求
    ├── components
    │  ├── App.vue
    │  └── ...
    └── store
     ├── index.js     # 我们组装模块并导出 store 的地方
     ├── actions.js    # 根级别的 action
     ├── mutations.js   # 根级别的 mutation
     └── modules
       ├── cart.js    # 购物车模块
       └── products.js  # 产品模块

    在 store下创建 modules 目录,该目录下创建 home.js

    const state = {
          count: 1
        }
        const getters ={
          desc(state) {
            if(state.count < 50) {
              return '吃饭'
           }else if(state.count < 100) {
              return '睡觉'
           }else {
              return '打豆豆'
           }
         }
        }
    
    const mutations = {
      increment(state, n) { // n 为载荷
        // state.count ++
        state.count += n
     },
      decrement(state) {
        state.count --
     }
    }
    
    const actions = {
      add(context) {
        // 触发 mutations 中的 increment 改变 state
        context.commit('increment', 10)
     },
      decrement({commit, state}) { // 按需传值
        commit('decrement')
     }
    }
        
    export default {
            // 存放状态(共享属性)
              state,
              //派生属性
              getters,
              // 改变 state 状态
              mutations,
              actions
    }

    修改 storeindex.js, 导入 ./modules/home.js,删除之前的home变量

    import Vue from 'vue'
    import Vuex from 'vuex'
    // 导入 Module
    import home from './modules/home'
    
    // 引入 Vuex 插件
    Vue.use(Vuex)
    
    
    const store = new Vuex.Store({ // 注意V 和 S都是大写字母
      modules: {
        home // home: home
     }
    })
    export default store

    正常访问, 与重构前一样

  • 相关阅读:
    Lua metatable & metamethod
    lua 中的点、冒号与self
    Eclipse 快捷键
    logging的使用
    URL转义字符
    UnicodeEncodeError: ‘ascii’ codec can’t encode
    Baidu URL的部分参数
    使用JS伪造Post请求
    print 不换行
    exception keynote
  • 原文地址:https://www.cnblogs.com/zouzou-busy/p/11826654.html
Copyright © 2020-2023  润新知