【前端】Vuex模块化和持久化应用示例

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

1. 概述

Vuex作为VUE状态管理组件能够将项目中公共数据状态进行统一管理并且可以按照不同的业务功能将数据状态分模块管理即数据状态模块化。

另外对于网页刷新导致Vuex状态丢失的问题可以使用vuex-persistedstate插件配置将数据保存在localStorage或者sessionStorage中即数据状态持久化。

同时使用secure-ls插件将明文数据加密以防数据泄露风险。

本文测试环境如下

Node版本v10.14.2
Npm版本6.4.1
package.json依赖的插件版本如下
“vue”: “^2.2.37”,
“vue-router”: “^3.0.1”,
“vuex”: “^3.0”,
“vuex-persistedstate”: “^4.1.0”
“secure-ls”: “^1.2.6”,

2. Vuex的模块化

Vuex的模块化将按照顺序分为3个部分Vuex组件实例化与引用、子模块的创建、模块化的使用方法。

2.1 Vuex组件实例化与引用

首先创建Vuex状态实例文件src/store/index.js用于创建状态实例并将根状态的四个参数(state, getters, mutations, actions)以及各个模块实例添加到modules对象参数中。详见以下代码。

// src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import user from "./modules/user";
import room from "./modules/room"

// 使用Vuex组件
Vue.use(Vuex)
const state = () => ({})
const getters = {}
const mutations = {}
const actions = {}

// 实例化状态对象
export default new Vuex.Store({
  // 根模块的四类对象
  state,  getters,  mutations,  actions,
  modules: {  // 将各个模块放入modules属性中
    user, room
  }
})

至于以上代码中引入的userroom子模块下文将进行介绍。

接下来要将Vuex组件实例添加到Vue实例中具体操作见如下代码。

// src/main.js
import Vue from 'vue'
import store from "./store";
/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

2.2 子模块的创建

上文.src/store/index.js文件中有user和room2个模块模块之间大同小异下面主要以user子模块进行讲解。本节主要介绍子模块的创建具体使用方法将在2.3节有详细介绍。

// src/store/modules/user.js
// user子模块
const state = () => ({})		// 详见2.2.1小节
const getters = {}				// 详见2.2.2小节
const actions = {}				// 详见2.2.3小节
const mutations = {}			// 详见2.2.4小节
export default {
  namespaced: true,
  state,
  getters,
  mutations,
  actions
}

2.2.1 state数据状态对象

state作为数据状态的存储是一个匿名函数返回的对象。

如下代码所示该对象中两个数据状态curTheme和curUser其中curTheme是字符串类型curUser是对象类型。

// src/store/modules/user.js
// state: 用户相关状态
const state = () => ({
  curTheme: 'light',
  curUser: {
    id: '123456',
    name: '张三'
  }
})

2.2.2 getters计算属性对象

getters作为计算属性类似vue组件中的computed属性。

如下代码所示该对象中是一个个的方法函数该函数按照顺序有(state, getters, rootState, rootGetters)四个参数。

// src/store/modules/user.js
const getters = {
  // 获取当前用户ID   
  curUserId: (state, getters, rootState, rootGetters) => {
    return state.curUser ? state.curUser.id : undefined
  },
  // 比对userId是否是当前用户id
  isCurUserId: (state, getters, rootState, rootGetters) => {
  	return (userId) => {
	  return userId == getters.curUserId;
	}
  },
  // 根据userId获取当前主题
  getCurThemeByUserId: (state, getters, rootState, rootGetters) => {
  	return (userId) => {
	  if(getters.isCurUserId(userId)) return state.curTheme;
	  else return '';
	}
  }
}

其中前两个参数stategetters是本模块中的数据状态对象即2.2.1节中介绍的state对象和计算属性对象即本节介绍的getters对象这两个参数是局部参数只能访问本模块中的数据状态和计算属性对象。

后两个参数rootStaterootGetters可以用来访问根模块和其他子模块的数据状态和计算属性对象。

2.2.3 actions异步请求对象

actions内部是也是一个个函数主要用于执行异步请求逻辑。而且如果需要更改数据状态则必须通过commit调用相应的mutation对象。

另外该函数有两个参数(context, payload)其中context是一个对象即{state, rootState, commit, dispatch, getters, rootGetters}等6个参数具体解释见如下代码中注释palyload为调用时的自定义输入参数。

需要注意的是actions中的(context, payload)参数中context是对象所以里面的参数可以是无序的。但是getters中的(state, getters, rootState, rootGetters) 是四个参数并且是有序的千万注意顺序

// src/store/modules/user.js
// actions异步操作通过mutation进行更新数据
const actions = {
  //context:{
  //         state,   		本模块数据状态对象例如state.curTheme
  //         rootState,   	根模块数据状态对象例如rootState.user.curTheme
  //         commit,   		用于调用mutation函数例如commit('SET_CUR_USER', null)
  //         dispatch,   	用于调用action函数例如dispatch('logout')
  //         getters   		本模块计算属性对象例如getters.curUserId
  //		 rootGetters 	根模块计算属性对象例如rootGetters['user/curUserId']
  // }
  // 用户登录
  async login ({state, rootState, commit, dispatch, getters, rootGetters}, {name, passwd})  {
 	// 用户登录逻辑
 	let res = await $api.login();
 	if(!res.success) Message.error('登录失败');   
  },
  // 登出
  async logout({commit}) {
    let res = await $api.logout()
  },

2.2.4 mutations数据同步对象

mutations数据同步对象内部是一个个同步函数该函数没有返回值内部逻辑主要是为了修改state属性。

注意千万不要在actions或者其他地方直接设置state数据状态。若要修改state状态必须使用commit调用mutations函数因为只有在mutations函数中修改才能触发Vuex数据和视图同步更新。

// src/store/modules/user.js
// mutations定义更新数据方法同步操作
const mutations = {
  SET_CUR_THEME (state, curTheme) {
    state.curTheme = curTheme
  },
  SET_CUR_USER (state, curUser) {
  	// curUser是对象类型需要使用Vue.set方法赋值数组类型也一样需要
    Vue.set(state, 'curUser', curUser)
  },
}

2.3 模块化的使用方法

Vuex模块化后不仅可以在自定义组件中使用而且可以引入store实例使用。

2.3.1 在自定义组件中使用

// RoomGaming.vue
<template>...</template>
<script>
import {mapActions, mapGetters, mapState, mapMutations} from "vuex";
export default {
  computed: {
  	// 展开user模块的curTheme和curUser
    ...mapState('user', ['curTheme', 'curUser']),
    // 展开user模块的三个计算属性
    ...mapGetters('user', ['curUserId', 'isCurUserId', 'getCurThemeByUserId']),
  },
  methods: {
  	// 展开user模块的login和logout两个异步函数
    ...mapActions('user', ['login', 'logout']),
    // 展开user模块的SET_CUR_THEME和SET_CUR_USER函数
    ...mapMutations('user', ['SET_CUR_THEME', 'SET_CUR_USER']),
    // 如何使用
    test() {
    	// 通过属性访问getters
    	let id = this.curUserId;  // mapGetters展开
    	let id = this.$store.getters['user/curUserId']
    	// 通过函数访问getters
    	let flag =  this.isCurUserId();// mapGetters展开
    	let flag = this.$store.getters['user/curUserId']();
    	// 通过dispatch触发actions
    	let res = await this.$store.dispatch('user/login');
    	let res = await this.login(); // mapActions展开
    	// 通过commit提交mutations
    	this.$store.commit('user/SET_CUR_THEME', 'dark');
    	this.SET_CUR_THEME('dark');	// mapMutations展开
    }
  },
}
</script>

2.3.2 引入store实例使用

不仅在自定义组件中使用而且可以引入store实例在任何js文件中使用。使用方法如同自定义组件中的this.$store

// ReceiveService.js
import $store from '../store'
const testFunction = (data) => {
  // mutations
  $store.commit("gamexstx/SET_CLOCKWISE", data.clockwise);
  $store.commit("gamexstx/SET_BOTTOM", data.bottom);
  $store.commit("gamexstx/SET_DEGREE", data.degree);
  $store.commit("gamexstx/SET_PLAYER_STATE", data.playerState);
  // getters
  let index = $store.getters['gamexstx/curDrawIndex']
  let code = $store.getters['gamexstx/getCardInGroup1ByIndex'](index);
  // actions
  await $store.dispatch('cardxstx/playDrawCardAnim', {code, target});
  // state
  if($store.state.gamexstx.degree > 0) return;
}

3. Vuex持久化配置

src/store/index.js中添加plugins属性并设置keystorage属性key是键名storage是存储位置可以是window.localStorage也可以是window.sessionStorage

// src/store/index.js
import createPersistedState from 'vuex-persistedstate'

export default new Vuex.Store({
  state,
  getters,
  mutations,
  actions,
  modules: {
    user, room, chat, gamexstx, cardxstx
  },
  plugins: [
    createPersistedState({
      key: 'vuex',
      storage: window.localStorage,
    })
  ]
})

因为localStorage不会随着网页刷新而丢失数据所以将Vuex数据状态存储在此解决刷新丢失数据的问题。如下图可以看到相应的数据存储。
在这里插入图片描述
另外由于是明文存储可能存在安全问题可以使用secure-ls插件对数据进行加密存储。

// src/store/index.js
import SecureLS from "secure-ls"
var ls = new SecureLS({
  encodingType: "aes",    //加密类型
  isCompression: false,   //是否压缩
  encryptionSecret: "encryption",   //PBKDF2值  加密秘密
});

export default new Vuex.Store({
  state,
  getters,
  mutations,
  actions,
  modules: {
    user, room, chat, gamexstx, cardxstx
  },
  plugins: [
    createPersistedState({
      // 以下使用ls加密
      key: 'vuex',
      storage: {
        getItem: (key) => ls.get(key),
        setItem: (key, value) => ls.set(key, value),
        removeItem: (key) => ls.remove(key),
      }
    })

  ]
})

加密之后控制台显示如下可以看到vuex中内容已加密。
在这里插入图片描述

项目传送门https://github.com/louislee92/vue-module-persistedstate

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: vue