• 小白整理了VUEX


    在小白开发的项目中前端使用的是Vue,虽然在日常工作中可以使用Vue进行开发工作。但是没有系统的学习过Vue,对Vue的一些特性和方法使用时常常需要查询资料解决问题,查询资料常常会占用大量时间,尤其对Vuex的使用。虽然可以通过很多Vue框架中带有的Vuex框架直接使用,但是用的越多,小白就会觉得越混乱、越不明白,只知其用不知其意。于是小白决定系统学习一下Vuex,来补充一下Vue知识。

    1.Vuex是什么?

    Vuex是一个用于Vue.js应用程序的状态管理模式。它可以集中管理Vue应用程序中的所有组件的状态,并提供了一种机制来保持状态的一致性和可追踪性。

    2.Vuex中有哪些对象?

    一个Vuex模块中通常包含以下五个对象:namespaced、state、mutations、actions 和 getters。这些对象分别用于定义模块的命名空间、状态、变更操作、异步操作和计算属性。

    除了这五个对象,还有一些其他可选的对象可以在模块中使用:

    1. modules:如果你的模块需要进一步细分为子模块,可以使用 modules 对象来组织和嵌套这些子模块。
    2. plugins:你可以使用 plugins 数组来安装Vuex插件,这些插件可以监听和修改状态的变化。
    3. actions的辅助对象:在 actions 中,你可以定义 rootrootStatecommitdispatch 等参数,来访问根模块的状态和调用根模块的 mutationsactions
    4. mutations的辅助对象:在 mutations 中,你可以定义 rootState 参数,来访问根模块的状态。
      plugins: [
        // ...
      ],
    
      actions: {
        someAction({ rootState, commit, dispatch }) {
          // ...
        },
      },
    
      mutations: {
        someMutation(state, { rootState }) {
          // ...
        },
      },

    3.从定义层面使用Vuex

    1. 安装Vuex:使用npm或yarn安装Vuex。
    2. 创建一个state:在你的Vue应用程序中创建一个 store 文件夹,并在其中创建一个 store.js 文件。
    3. 定义状态(State):在 store.js 文件中,定义一个包含需要共享的状态的对象。
    4. 定义mutations:在 store.js 文件中,定义一系列用于修改状态的mutations函数。每个mutation函数接收一个state对象作为参数,并根据需要修改状态。
    5. 定义actions:在 store.js 文件中,定义一系列用于处理异步操作的actions函数。每个action函数可以调用一个或多个mutations函数来修改状态。
    6. 定义getters:在 store.js 文件中,定义一系列用于获取state对象的“getters普通对象形式”或用于获取state的计算属性“getters函数”,可以通过“getters”来定义state状态的衍生值或计算属性并获取。getters不是必须的。
    7. 注册store:在你的Vue应用程序的入口文件(main.js)中,导入 store.js 并使用Vue.use()方法注册Vuex。
    8. 在组件中使用状态:使用 this.$store.state 来访问状态,使用 this.$store.commit() 来调用mutations,使用 this.$store.dispatch() 来调用actions。
    9. 示例如下:

     

    store.js

    import Vue from 'vue';
    import Vuex from 'vuex';
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
        state: {
          count: 0
        },
        mutations: {
          increment(state) {
            state.count++;    
          },
          decrement(state) {
            state.count--;
          },
          incrementByParam(state, amount) {
            state.count += amount;
          },
          decrementByParam(state, amount) {
            state.count -= amount;
          }
        },
        actions: {
          increment(context) {
            context.commit('increment');
          },
          incrementAsync(context) {
            setTimeout(() => {
              context.commit('increment');
            }, 1000);
          },
          decrement(context) {
            context.commit('decrement');
          }
        },
        getters: {
          // 对象形式的getters,允许以属性的方式访问计算后的值,而无需调用函数
          getCount: state => state.count,
          // 函数形式的getters,可以接受额外的参数,并根据传入的参数进行计算返回结果
          getCountByParam: (state) => (num) => {
            return state.count + num;
          }
        }
    })

     

    main.js

     import store from "xxxxx/store";
    
    new Vue({
      store,
      // ...其他Vue应用程序的配置...
    }).$mount('#app');

    组件中使用getters

    computed: {
        //函数形式的 getters 调用
        addNum() {
            return this.$store.getters.getCountByParam(2);
        },
        //对象形式的 getters 调用
        getNum() {
            return this.$store.getters.getCount;
        }
        //getters不是必须的
        num() {
            return this.$store.state.count
        }
    }

    触发Mutations、Actions

    //在Vue组件中通过 commit 方法触发Mutations来修改状态
    methods: {
        increment() {
          this.$store.commit('increment');
        },
        decrement() {
          this.$store.commit('decrement');
        },
        //带参数的increment
        incrementByParam() {
          this.$store.commit('incrementByParam', 5);
        },
        incrementAsync() {
          this.$store.dispatch('incrementAsync');
        },
        incrementAction() {
          this.$store.dispatch('increment');
        }
    }

    4.项目中使用时,为了项目的扩展性,通常使用Vuex模块来分割和组织状态,如果使用了模块分割需要注意模块命名空间。下面是使用模块的初级示例,其中getters演示了命名空间的使用。

    初级:使用模块分割

    **store.js:**
    
    import Vue from 'vue';
    import Vuex from 'vuex';
    import userModule from './user';
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
      modules: {
        user: userModule,
      },
    });
    
    **user.js:**
    
    export default {
      namespaced: true,
    
      state: {
        username: '',
        email: '',
      },
    
      mutations: {
        setUsername(state, payload) {
          state.username = payload;
        },
    
        setEmail(state, payload) {
          state.email = payload;
        },
      },
    
      actions: {
        updateUser({ commit }, payload) {
          commit('setUsername', payload.username);
          commit('setEmail', payload.email);
        },
      },
      getters: {
        getUserName: state => state.username
      }
    };
    
    **组件中的使用示例:**
    
    computed: {
      username() {
        return this.$store.state.user.username;
      },
      username2() {
        //如果使用了模块命名空间,就需要采用this.$store.getters['module/getterName']的方式来访问getter函数;
        //如果没有使用模块命名空间,可以直接通过this.$store.getters.getterName访问getter函数
        return this.$store.getters['user/getUserName']
      }
    },
    
    methods: {
      updateUser() {
        this.$store.dispatch('user/updateUser', { username: 'John', email: 'john@example.com' });
      },
    },

    5.真实的项目我们可能需要多个modules,并且每个modules中getters、mutations、actions 和 state 通常会变得非常大,所以它们也需要用单个文件分割。

    store.js

    import Vue from "vue";
    import Vuex from "vuex";
    import loggerPlugin from './plugins/logger';
    
    //以下五个文件是当前目录下state、getters、mutations、actions分割出来后的文件
    import state from "./state";
    import getters from "./getters";
    import mutations from "./mutations";
    import actions from "./actions";
    
    Vue.use(Vuex);
    
    const myPlugin = store => {
      store.subscribe((mutation, state) => {
        // 在这里可以监听 mutation 的变化和访问 state
      });
    };
    
    //下面是将整个模块分割出来
    import moduleCard from "xxx/cart/moduleCart.js"
    import module2 from "xxx/xxx/module2.js"
    import { module3 } from "已安装组件"
    
    export default new Vuex.Store({
      namespaced: true,
      state,
      getters,
      mutations,
      actions,
      plugins: [loggerPlugin, myPlugin],
      modules: {
        cart: moduleCart,
        moduleName2: module2,
        //这个代码片段中的 ...module3 是使用 ES6 的扩展运算符将 module3 模块中的内容解构到 modules 对象中。
        //这样做可以方便地将 module3 模块的 state、mutations、getters 和 actions 添加到 Vuex 的模块集合中。
        ...module3,
      },
      //在 Vue.js 中,strict 是一个用于开启严格模式的选项。当 strict 设置为 true 时,Vuex 的状态变更会被严格监测,以便捕捉到状态的不合规变更。
      //在你提供的代码中,process.env.NODE_ENV !== "production" 是一个条件判断语句,它用于根据当前运行环境来确定是否开启严格模式。通常,在开发环境中,我们会将 process.env.NODE_ENV 设置为 "development",而在生产环境中会设置为 "production"。
      //当 process.env.NODE_ENV !== "production" 为 true 时,说明当前不处于生产环境,此时 strict 会被设置为 true,即开启严格模式。这样做的目的是为了方便在开发阶段捕捉到状态变更的错误,以及进行更加详细的状态变更追踪和错误提示。
      //一般来说,建议在开发环境中开启严格模式,而在生产环境中关闭严格模式,以获得更好的性能和体验。这可以通过构建工具(如 webpack)来设置 process.env.NODE_ENV 的值来实现。
      strict: process.env.NODE_ENV !== "production",
    });

    下面用moduleCart作为示例来演示一个Vuex模块中五个对象的分割: namespaced,state,mutations,actions 和 getters。创建一个文件夹名为cart,在文件夹中创建五个文件分别为moduleCart.js、moduleCartActions.js、moduleCartGetters.js、moduleCartMutations.js和moduleCartState.js

    moduleCart.js

     import state from "./moduleCartState.js";
    import mutations from "./moduleCartMutations.js";
    import actions from "./moduleCartActions.js";
    import getters from "./moduleCartGetters.js";
    
    export default {
      namespaced: true,
      state: state,
      mutations: mutations,
      actions: actions,
      getters: getters,
    };

    moduleCartActions.js

    在actions中可以使用store,以使用已存状态数据
    import store from "../store.js";
    
    export const addToCart = ({ commit }, product) => {
      commit('addProduct', product);
    };
    
    export const removeFromCart = ({ commit }, productId) => {
      commit('removeProduct', productId);
    };
    
    //或者下面方式
    export default {
        addToCart({ commit }, product) {
            commit('addProduct', product);
        },
        removeFromCart({ commit }, product) {
            commit('removeProduct', productId);
        },
        //包含辅助对象的action,使用`rootState`来访问根模块的状态,使用`state`来访问当前模块的状态
        addToCart2({ commit, rootState, state }) {
          commit('addProduct', product);
          console.log(rootState); // 访问根模块的状态
          console.log(state); // 访问模块的状态
        },
         removeFromCart2({ commit, rootState }) {
          commit('removeProduct', productId);
          console.log(rootState); // 访问根模块的状态
        },
    }

    moduleCartGetters.js

    export const cartProducts = state => state.products;
    
    export const totalItems = state => state.products.length;
    
    或者
    
    export default {
        cartProducts:state => state.products,
        totalItems: state => state.products.lengthcartProducts2(state, getters, rootState, rootGetters) {
          console.log(rootState); // 访问根模块的状态
          console.log(rootGetters); // 访问根模块的getters
          return state.products;
        },
    };

    moduleCartMutations.js

     export const addProduct = (state, product) => {
      state.products.push(product);
    };
    
    export const removeProduct = (state, productId) => {
      state.products = state.products.filter(p => p.id !== productId);
    };
    
    或者
    import Vue from "vue";
    export default {
        addProduct(state, product) {
            Vue.set(state, "products", product);
        },
        removeProduct(state, productId) {
            Vue.set(state, "products", state.products.filter(p => p.id !== productId))
        }
    }

    moduleCartState.js

     export default {
      products: [],
    };

    plugins

     **plugins/logger.js:**
    const loggerPlugin = store => {
      store.subscribe((mutation, state) => {
        console.log('mutation type:', mutation.type);
        console.log('mutation payload:', mutation.payload);
        console.log('state:', state);
      });
    };
    
    export default loggerPlugin;

    以上就是小白用心整理的Vuex的内容,通过整理小白对Vuex有了更多的了解,之前小白不理解不明白的地方现在明白了。小白会在编码的路上继续努力、继续加油!

  • 相关阅读:
    不再为文件名大小写烦恼:批量转换,一招搞定
    如何选择合适的官文转录供应商
    关于IDEA中gradle项目bootrun无法进入断点以及gradle配置页面不全的解决方案
    树莓派i2c通讯 设置 和 查看 i2c通信地址方法
    QT专栏2 -Qt for Android
    数据类型与变量
    2022 CCF CSP-J2 解密
    idea如何彻底完美地修改项目名,以及解决idea修改项目名后出现中括号[]的问题
    mysql数据库
    第十五届蓝桥杯模拟考试III_物联网设计与开发
  • 原文地址:https://www.cnblogs.com/pocn/p/17659585.html