vuex基本使用及模块化封装

1,322 阅读3分钟

应用场景

项目中存在多个页面使用同一数据或者共享某个组件,当某一处数据发生改变,期望其他地方响应式地发生改变,如果使用路由传值或本地存储导致项目难度加大,不妨试试vuex。

需求分析

  1. 如何引入vuex?

  2. 在vue-cli中如何使用?

开发流程

  1. 引入vuex
    1.1 npm install vuex -S
    1.2 在src文件夹下创建store文件夹,用于存放与vuex相关的js文件,这里主要介绍两种方式:
    一、简单项目的store结构
    只需在store文件夹下放一个单独的文件index.js即可,如下所示:

import Vue from 'vue'import Vuex from 'vuex'import {
  getUserInfo,
  getNotReadMessageNum
} from '../service/getData'import {setStore, getStore} from '../config/mUtils'Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    userInfo: {},// 用户信息
    msg_not_read_num: 0, // 未读消息数
    session_id: '', // PHPSESSID
  },
  actions: {
    async getUserInfo ({
      commit,
      state
    }) {      let res = await getUserInfo();      let info = res.data;
      commit('GET_USERINFO', info);
    },
    async getMsgNotReadNum ({
      commit,
      state
    }) {      let res = await getNotReadMessageNum();      let num = res.data.message_num;
      commit('GET_MSG_NOT_READ_NUM', num);
    }
  },
  mutations: {    // 获取用户信息
    GET_USERINFO (state, info) {
      state.userInfo = info;
    },    // 获取消息未读数
    GET_MSG_NOT_READ_NUM (state, num) {
      state.msg_not_read_num = num;
    },    // 记录PHPSESSID
    RECORD_SESSION_ID (state, session_id) {
      state.session_id = session_id;
      setStore('session_id', state.session_id);
    }
  },
  getters: {

  }
})

二、复杂项目的store结构
将vuex模块化,封装多个js文件,好处:条理清晰,结构明了
—store
—-index.js
—-actions.js
—-mutation-types.js
—-mutations.js
—-getters.js

index.js

import Vue from 'vue'import Vuex from 'vuex'import mutations from './mutations'import actions from './action'import getters from './getters'import {getStore} from '../mConfig/mUtils'Vue.use(Vuex)const state = {
    userInfo: {
        username: ''
    }, //用户信息
    shopInfo: null, // 我的小店信息
    choosedAddress: getStore('choosedAddress') != undefined ? JSON.parse(getStore('choosedAddress')) : null, // 当前选择的地址
    choosedClientAddress: getStore('choosedClientAddress') != undefined ? JSON.parse(getStore('choosedClientAddress')) : [], // 代客下单选择的地址
    choosedCartList: getStore('choosedCartList') != undefined ? JSON.parse(getStore('choosedCartList')) : null, // 当前购物车选择结算的 item 列表
    itemType: [], // 商品分类
    couponIds: getStore('couponIds') != undefined ? JSON.parse(getStore('couponIds')) : [], // 已选择的优惠券id}

export default new Vuex.Store({
    state,
    getters,
    actions,
    mutations,
})

actions.js

import {
  getShopinfo,
  getShopSortList
} from '../service/myApi';
import {
  GET_SHOPINFO,
  INIT_ITEM_TYPE
} from './mutation-types';
import Vue from 'vue';const vm = new Vue();

export default {
  async getShopInfo({
    commit,
    state
  }) {    let res = await getShopinfo();    if (res.code === 0) {
      commit(GET_SHOPINFO, res.data);
    } else {
      vm.$toast(res.error_msg);
    }
  },
  async getItemType({
    commit,
    state
  }) {    let res = await getShopSortList();    if (res.code === 0) {      let {
        list
      } = res.data;
      commit(INIT_ITEM_TYPE, list);
    } else {
      vm.$toast(res.error_msg);
    }
  }
}

mutation-types.js

export const CHOOSE_ADDRESS = 'CHOOSE_ADDRESS'; // 采购进货选择地址export const CHANGE_CART_LIST = 'CHANGE_CART_LIST'; // 购物车选择 itemexport const GET_SHOPINFO = 'GET_SHOPINFO'; // 获取我的小店信息export const INIT_ITEM_TYPE = 'INIT_ITEM_TYPE'; // 初始化商品分类export const ADD_ITEM_TYPE = 'ADD_ITEM_TYPE'; // 添加商品分类export const RESET_ITEM_TYPE = 'RESET_ITEM_TYPE'; // 重置商品分类export const CHANGE_CLIENT_ADDRESS = 'CHANGE_CLIENT_ADDRESS'; // 改变代客下单选择的地址export const EDIT_CLIENT_ADDRESS = 'EDIT_CLIENT_ADDRESS'; // 编辑某个代客下单选择的地址export const UPDATE_COUPON_IDS = 'UPDATE_COUPON_IDS'; // 修改couponIdsexport const CLEAR_CLIENT_ADDRESS = 'CLEAR_CLIENT_ADDRESS'; // 清空代客下单选择的地址

mutations.js

import * as types from './mutation-types'import { setStore } from "../mConfig/mUtils";
import Vue from 'vue';
import VueRouter from 'vue-router';const vm = new Vue();const router = new VueRouter();const typeIsExist = (types, type) => {    for(let i = 0; i < types.length; i++) {        if (types[i].title === type) {            return true;
        }
    }    return false;
}
export default {
    [types.CHOOSE_ADDRESS] (state, address) {
        console.log(address);
        state.choosedAddress = address;
        setStore('choosedAddress', state.choosedAddress);
    },
    [types.CHANGE_CART_LIST] (state, cart_list) {
        state.choosedCartList = cart_list;
        setStore('choosedCartList', state.choosedCartList);
    },
    [types.GET_SHOPINFO] (state, info) {
        state.shopInfo = {...info};
    },
    [types.ADD_ITEM_TYPE] (state, type) {        if (!typeIsExist(state.itemType, type)) {
            state.itemType.push({
                title: type,
                checked: false
            });
            vm.$toast('添加成功');
            setTimeout(() => {
                router.back();
            }, 500);
        } else {
            vm.$toast('该分类已经存在');
        }
    },
    [types.RESET_ITEM_TYPE] (state, types) {
        state.itemType = [...types];
    },
    [types.INIT_ITEM_TYPE] (state, types) {        let tmpList = [...types];        for(let i = 0; i < tmpList.length; i++) {
            tmpList[i] = {
                ...tmpList[i],
                checked: false
            };
        }
        state.itemType = [...tmpList];
    },
    [types.CHANGE_CLIENT_ADDRESS] (state, address) {
        state.choosedClientAddress.push(address);
        setStore('choosedClientAddress', state.choosedClientAddress);
    },
    [types.EDIT_CLIENT_ADDRESS] (state, {index, address}) {
        console.log(index, address);
        state.choosedClientAddress.splice(index, 1, address);
        setStore('choosedClientAddress', state.choosedClientAddress);
    },
    [types.UPDATE_COUPON_IDS] (state, coupon_id) {        if (state.couponIds.indexOf(coupon_id) < 0) {
            state.couponIds.push(coupon_id);
        }
        setStore('couponIds', state.couponIds);
    },
    [types.CLEAR_CLIENT_ADDRESS] (state) {
        state.choosedClientAddress = [];
        setStore('choosedClientAddress', state.choosedClientAddress);
    }
}

gettes.js

export default {

}

1.3 main.js中引入

import store from './store'new Vue({
  router,
  store,
}).$mount('#app')
  1. 项目使用

import { mapState, mapMutations } from 'vuex';
computed: {
    ...mapState([        'choosedCartList'
    ])
},
methods: {
    ...mapMutations([      'CHOOSE_ADDRESS',      'CHANGE_CART_LIST',      'CHANGE_CLIENT_ADDRESS',      'EDIT_CLIENT_ADDRESS'
    ]),    // 选择地址
    async chooseAddress(index) {      this.activeIndex = index;      // 代客下单
      if (this.from_page === '/confirm_valet_order' || this.from_page === '/addClient') {        let choosedIndex = this.$route.query.choosedIndex;        if (window.localStorage.getItem('is_single') != undefined && window.localStorage.getItem('is_single')) {          if (choosedIndex >= 0) {
            console.log(this.address_list[index]);            this.EDIT_CLIENT_ADDRESS({index: choosedIndex, address: this.address_list[index]});
          } else {            this.CHANGE_CLIENT_ADDRESS(this.address_list[index]);
          }
        } else {          this.EDIT_CLIENT_ADDRESS({index: 0, address: this.address_list[index]});
        }

      } else if (this.from_page === '/confirm_purchase_order' || this.from_page === '/wxControlAddress') { // 采购进货
        this.CHOOSE_ADDRESS(this.address_list[index]);
      }

      setTimeout(() => {        this.$router.back();
      }, 500);
    }
  }

总结

  1. 本文主要介绍了vue-cli如何引入vuex并在项目中使用,包括项目结构及模块化的结构划分;

  2. 请务必遵守以下规则:
    1) 应用层级的状态应该集中到单个 store 对象中。
    2) 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
    3) 异步逻辑都应该封装到 action 里面。