我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Vuex模块化与持久化深入讲解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Vuex模块化与持久化深入讲解

概述

Vuex作为VUE状态管理组件,能够将项目公共数据进行统一管理。而且可以按照不同的业务功能将数据状态分模块管理。另外,对于网页刷新导致Vuex状态丢失的问题可以使用vuex-persistedstate插件配置将数据保存在localStorage或者sessionStorage中。

本文测试环境如下:

“vue”: “^2.2.37”,
“vue-router”: “^3.0.1”,
“vuex”: “^3.0”,
“vuex-persistedstate”: “^4.1.0”
“secure-ls”: “^1.2.6”,

Vuex的模块化

首先是main.js文件中引用Vuex组件,引入./store/index.js作为store参数,用于实例化VUE对象。

// main.js
import Vue from 'vue'
import store from "./store";

new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

其中./store/index.js文件是Vuex状态实例,使用new Vuex.Store()进行状态实例化,并将根状态的state,getters,mutations,actions添加到参数,以及各个模块添加到modules对象参数中。

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, chat
  }
})

以上./store/index.js文件中,有user,room,chat三个模块,模块之间大同小异,下面仅以user模块进行讲解。其中

state数据状态对象

state,作为数据状态的存储,是一个匿名函数返回的对象,该对象中有一个curTheme主题字符串和一个 curUser用户对象。

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

getters计算属性对象

getters,作为计算属性,类似vue组件中的computed属性。该对象中是一个个的方法函数,该函数按照顺序有(state, getters, rootState, rootGetters)四个参数。前两个参数stategetters是本模块中的数据状态对象和计算属性对象,可在方法中按照如下格式进行引用。

curUserId中可以使用state.curUser来访问当前模块中数据状态对象中的curUser对象。

使用方法:state.curUserId

isCurUserId中返回的是一个函数,该函数接收一个userId参数,通过getters.curUserId可以访问当前计算属性对象中的curUserId属性。

使用方法:state.isCurUserId(userId)

getCurThemeByUserId中返回的是一个函数,该函数接收一个userId参数,通过getters.isCurUserId(userId)函数确认是否是当前用户,并返回对应主题。

使用方法:state.getCurThemeByUserId(userId)

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 '';
	}
  }
}

后两个参数rootStaterootGetters可以用来访问根和其他模块的数据状态和计算属性。比如下面是room模块的getters属性。

// room.js
const getters = {
  // 测试
  testRoom: (state, getters, rootState, rootGetters) => {
	// 获取userid
	let curUserId = rootGetters['user/curUserId']
	// 根据userId获取当前主题
	let curTheme = rootGetters['user/getCurThemeByUserId'](curUserId)
	return 'test';
  }
}

actions异步请求对象

actions,内部是一个个函数,所有异步操作需要放到这里,且如果需要更改数据状态,则必须通过commit调用相应的mutation。且需要注意该函数有两个参数(context, payload),其中context是一个对象,包括了state,‘rootState’,‘commit’,‘dispatch’,‘getters’,'rootGetters’等参数。

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

// actions,异步操作,通过mutation进行更新数据
const actions = {
  //context:{
  //         state,   等同于store.$state,若在模块中则为局部状态
  //         rootState,   等同于store.$state,只存在模块中
  //         commit,   等同于store.$commit
  //         dispatch,   等同于store.$dispatch
  //         getters   等同于store.$getters,若在模块中为局部状态
  //		 rootGetters 等同于store.$getters
  // }
  // 用户登录
  async login ({state, rootState, commit, dispatch, getters, rootGetters}, {name, passwd})  {
    // getters使用
    getters.curUserId				// 获取当前模块中的curUserId计算属性 
    rootGetters['user/curUserId']	// 获取user模块中的curUserId计算属性
	// dispatch使用
    dispatch('logout') 		// 调用本模块中的logout异步请求
    dispatch('room/getRoomByUserId', null, { root: true }) // 调用rooom模块的getRoomByUserId异步请求
	// commit使用
    commit('SET_CUR_USER', null) // 调用本模块mutation方法
    commit('room/SET_ROOM_LIST', null, { root: true }) // 调用room模块mutation方法
  },
  // 登出
  async logout({commit}) {
    let res = await $api.logout()
    localStorage.removeItem("token");
    commit("SET_CUR_USER", null);
    // 关闭socket链接
    websocket.close();
    await $router.push("/")
  },

mutations数据同步对象

mutations,数据同步对象,内部是一个个同步函数,该函数中主要是为了修改state属性。注意千万不要在actions或者其他地方直接设置state数据状态,若要修改state状态,必须使用commit。因为只有在mutations方法中修改才能触发Vuex数据和视图同步更新。

其他地方更新数据,需要使用commit方法

commit('room/SET_ROOM_LIST', null)

另外,对象和数组类型修改时不能使用state.curUser = curUser这种方式。需要使用Vue.set()方法进行修改,否则也不会触发数据视图的更新。

Vue.set(state, 'curUser', curUser)
Vue.set(state.curUser, 'name', '张三')
Vue.set(state.list, 0, "2");
// mutations,定义更新数据方法,同步操作
const mutations = {
  SET_CUR_THEME (state, curTheme) {
    state.curTheme = curTheme
  },
  SET_CUR_USER (state, curUser) {
    Vue.set(state, 'curUser', curUser)
  },
}

Vuex的使用方式

在自定义组件中使用

// RoomGaming.vue
import {mapActions, mapGetters, mapState, mapMutations} from "vuex";
export default {
  computed: {
    ...mapState('user', ['curUser']),
    ...mapState('room', ['roomVO']),
    ...mapGetters('room', ['seatCount', 'playerList', 'curPlayer', 'curPlayerStatus',
      'curPlayerCanAddSeat', 'curPlayerCanDelSeat', 'curPlayerIsOwner']),
  },
  methods: {
    ...mapActions('room', ['leaveRoom', 'playerReady', 'playerAddSeat', 'startGame']),
    ...mapMutations('room', [])
  },
}

在自定义js文件中引用

// 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;
}

Vuex持久化配置

在main.js中添加plugins属性,并设置keystorage属性,key是键名,storage是存储位置,可以是window.localStorage也可以是window.sessionStorage

// main.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数据状态存储在此解决刷新丢失数据的问题。如下图,可以看到相应的数据存储。

另外,由于是明文存储,可能存在安全问题,可以使用以下插件对数据进行加密存储。

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中内容已加密。

main.js代码

import Vue from 'vue'
import Vuex from 'vuex'
import user from "./modules/user";
import room from "./modules/room"
import chat from "./modules/chat"
import cardxstx from "./modules/cardxstx"
import gamexstx from "./modules/gamexstx";
import createPersistedState from 'vuex-persistedstate'
import SecureLS from "secure-ls";
import SystemConfig from "../consts/SystemConfig";
Vue.use(Vuex)
const state = () => ({})
const getters = {}
const mutations = {}
const actions = {}
var ls = new SecureLS({
  encodingType: "aes",    //加密类型
  isCompression: false,   //是否压缩
  encryptionSecret: "encryption",   //PBKDF2值  加密秘密
});
localStorage.removeItem(SystemConfig.storageKey);
export default new Vuex.Store({
  state,
  getters,
  mutations,
  actions,
  modules: {
    user, room, chat, gamexstx, cardxstx
  },
  plugins: [
    createPersistedState({
      key: SystemConfig.storageKey,
      storage: window.localStorage,
      // 以下使用ls加密
      // key: SystemConfig.storageKey,
      // storage: {
      //   getItem: (key) => ls.get(key),
      //   setItem: (key, value) => ls.set(key, value),
      //   removeItem: (key) => ls.remove(key),
      // }
    })
  ]
})

modules/user.js代码

// ./store/modules/user.js
import Vue from 'vue'
import $api from '../../api/inter'
import $router from "../../router";
import {Message} from "element-ui";
import websocket from "../../api/websocket";
import SystemConfig from "../../consts/SystemConfig";
// state: 用户相关状态
const state = () => ({
  curTheme: 'light',
  curUser: undefined,
})
// getters: 用户相关计算属性,类似vue组件中的computed
const getters = {
  // 
  curUserId: (state, getters, rootState, rootGetters) => {
    return state.curUser ? state.curUser.id : undefined
  },
  getUserNameById: (state, getters, rootState, rootGetters) => {
	return (userId) => {
	  if(state.curUser.id == userId) return state.curUser.name;
	  else return "无名氏" 
	}
  }
}
// actions,异步操作,通过mutation进行更新数据
const actions = {
  //context:{
  //         state,   等同于store.$state,若在模块中则为局部状态
  //         rootState,   等同于store.$state,只存在模块中
  //         commit,   等同于store.$commit
  //         dispatch,   等同于store.$dispatch
  //         getters   等同于store.$getters
  // }
  // 获取用户信息
  async getCurUser ({ state, commit }) {
    // dispatch('room/getRoomByUserId', value, { root: true })  // 调用另外模块
    // 获取登录后存储在localStorage中的token值
    let token = localStorage.getItem("token");
    // console.log("token=" + token)
    // 如果token为空则返回空
    if(token == undefined || token == null) {
      commit('SET_CUR_USER', null);
      // Message.warning("用户token失效,将移除本地token");
      // 移除token
      localStorage.removeItem("token")
      // 关闭socket链接
      websocket.close();
      return;
    }
    try{
      // 将token传到后台获取对应用户信息
      let res = await $api.getUserInfoByToken();
      if(200 != res.code) throw new Error(res.message);
      localStorage.removeItem(SystemConfig.storageKey); // 登陆成功后清空会话缓存
      // 获取到用户信息,设置到curUser状态中
      commit('SET_CUR_USER', res.data);
      // 设置websocket
      websocket.connect(state.curUser.id)
    } catch(err) {
      // 会话失效后应该清理本地缓存
      localStorage.removeItem("token");
      // 关闭socket链接
      websocket.close();
      return Promise.reject(err);
    }
  },
  // 游客登录
  async loginAsNameless({ dispatch }) {
    try{
      let res = await $api.loginAsNameless()
      await dispatch('loginSuccess', res.data);
    } catch (err) {
      Message.error(err);
      return Promise.reject(err)
    }
  },
  // 用户登录
  async loginByUser({dispatch}, params) {
    try{
      let res = await $api.login(params)
      // console.log("用户登录返回:", res)
      await dispatch('loginSuccess', res.data);
    }catch (err) {
      Message.error(err)
      return Promise.reject(err)
    }
  },
  // 登录之后的操作
  async loginSuccess({state, dispatch}, token) {
    // 设置本地缓存
    localStorage.token = token;
    // 获取用户信息
    await dispatch('getCurUser');
    // 如果获取用户信息成功,则打开websocket并进入大厅
    if(state.curUser != null) {
      await $router.push({path: '/hall'})
    } else {
      $router.push({path: "/"})
    }
  },
  // 登出
  async logout({commit}) {
    let res = await $api.logout()
    localStorage.removeItem("token");
    commit("SET_CUR_USER", null);
    // 关闭socket链接
    websocket.close();
    await $router.push("/")
  },
  // 修改密码
  async modifyPass({commit}, params) {
    try{
      await $api.modifyPass(params)
    } catch (err) {
      Message.error(err)
      return Promise.reject(err)
    }
  }
}
// mutations,定义更新数据方法,同步操作
//
const mutations = {
  SET_CUR_USER (state, curUser) {
    Vue.set(state, 'curUser', curUser)
  },
}
export default {
  namespaced: true,
  state,
  getters,
  mutations,
  actions
}

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

到此这篇关于Vuex模块化与持久化深入讲解的文章就介绍到这了,更多相关Vuex模块化与持久化内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Vuex模块化与持久化深入讲解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Vuex模块化与持久化深入讲解

在实际项目开发过程中,如果公共数据比较多我们会使用vuex做公共状态管理,但是在对浏览器进行刷新操作的时候,会导致vuex内的数据丢失,这种情况有些时候是没问题的,但是有的时候我们需要某些数据可以持久化的保存,这样就需要做对应的处理
2023-01-06

Redis RDB与AOF持久化方式详细讲解

目录1.RDB持久化1.1 RDB文件的保存1.2 RDB文件的载入1.3 RDB持久化时服务器的状态1.4 RDB持久化策略2.AOF持久化2.1 持久化的实现2.2 文件的载入与数据还原2.3 AOF文件的重写1.RDB持久化&ems
2022-11-22

Redis中AOF与RDB持久化策略深入分析

目录写在前面一、Redis为什么要持久化二、Redis的持久化方式2.1. AOF持久化(Append of file)2.1.1 fsync 系统调用2.1.2 AOF持久化策略2.1.3 aof_rewrite2.2 RDB快照(red
2022-11-28

揭开 ES6 模块面纱:深入解析模块化概念

ES6 模块化是一种革命性的 JavaScript 特性,它通过将代码组织成模块来提升开发效率和可维护性。本文深入探讨 ES6 模块的核心概念,揭开其幕后运作原理,为开发人员提供全面指南。
揭开 ES6 模块面纱:深入解析模块化概念
2024-03-02

学生信息系统(json模块解决数据持久化

将学生管理的案例,学生信息由原来的只有姓名,拓展为包含,姓名,年龄,两个属性;完成对应的增、删、查、改,操作import json,os,time,sysstudent_list = []File_path = 'name.txt'#从文件
2023-01-31

JavaScriptES6中类与模块化管理超详细讲解

JavaScript中的模块化是指将每个js文件会被认为单独一个的模块。模块之间是互相不可见的。如果一个模块需要使用另一个模块,那么需要通过指定语法来引入要使用的模块,而且只能使用引入模块所暴露的内容
2023-01-11

Go函数性能优化:锁与同步原语的深入讲解

go 函数的性能优化依赖于锁和同步原语的正确使用。锁类型:1. 互斥锁(mutex):保证独占访问共享资源;2. 读写锁(rwmutex):允许并发读取但仅允许一个写入。同步原语:1. 条件变量(cond):暂停 goroutine 直到条
Go函数性能优化:锁与同步原语的深入讲解
2024-05-05

Android持久化技术之文件的读取与写入实例详解

本文实例分析了Android持久化技术之文件的读取与写入操作。分享给大家供大家参考,具体如下: 1、文件存储 (1)在Android的持久化技术中,文件存储是最基本的一种数据存储方式。 (2)对存储的内容部做任何处理,原样存储到文件中。 (
2022-06-06

深入解析 VUE 组件:构建高效模块化前端应用的利器

剖析 VUE 组件的特性与优势,助你构建高效模块化前端应用。
深入解析 VUE 组件:构建高效模块化前端应用的利器
2024-02-26

阿里云服务器配置信息板块深入解析与优化策略

阿里云服务器配置信息板块是阿里云提供的一套管理工具,可以帮助用户对服务器进行详细的配置和管理。本文将对这一板块进行深入解析,并分享一些优化策略。一、阿里云服务器配置信息板块介绍阿里云服务器配置信息板块是阿里云为用户提供的一项强大服务,可以帮助用户对服务器进行详细的配置和管理。它提供了丰富的服务器配置选项,包括操作
阿里云服务器配置信息板块深入解析与优化策略
2023-11-05

Node.js CommonJS 规范的学习资源大放送:5本好书,3个教程,带你深入理解模块化开发

Node.js CommonJS 规范是构建模块化应用程序的基础,帮助开发者轻松创建模块、实现代码复用。本文提供了 5 本好书和 3 个教程资源,帮助你深入理解 CommonJS 规范,掌握模块化开发技巧。
Node.js CommonJS 规范的学习资源大放送:5本好书,3个教程,带你深入理解模块化开发
2024-02-04

编程热搜

目录