为了满足业务需求,需要在刷新页面的时候不丢失已加载过的数据,所以编写了这个插件来满足业务需求(vuex版本:3.6.2)。
使用很简单,只需要在模块文件中定义一个meta数据,就实现了存储功能,会在初始化的时候使用存储的数据,在更新state的时候存储数据。
// 如果 storage = 'local' 则表示使用 localStorage 存储,否则使用 sessionStorage 存储
meta: {
storage: "session",
},
一个简单的例子
- 编写模块文件
store/modules/user.js
业务功能:登录后加载用户信息,登出后清空用户信息
import * as userApi from "@/apis/user";
export default {
meta: {
storage: "session",
},
namespaced: true,
state: {
token: null,
userInfo: null,
},
getters: {
isLogin(state) {
return !!state.token;
},
},
mutations: {
SET_TOKEN(state, data) {
state.token = data;
},
SET_USER_INFO(state, data) {
state.userInfo = data;
},
},
actions: {
async getUserInfo(context) {
const result = await userApi.getUserInfo();
context.commit("SET_USER_INFO", result.data);
},
cleanUserInfo(context) {
context.commit("SET_USER_INFO", null);
},
async login(context, data) {
const result = await userApi.login(data);
context.commit("SET_TOKEN", result.data.token);
context.dispatch("getUserInfo");
},
async logout(context) {
await userApi.logout();
context.commit("SET_TOKEN", null);
context.dispatch("cleanUserInfo");
},
},
};
- 编写
store/plugins/storage.js插件
实现原理:根据模块对象中的元数据来判断是否需要做持久化操作,需要则修改模块中的state属性为一个函数,函数的作用就是加载本地数据或者使用默认值,然后再监听模块的state,一旦修改则对数据序列化后进行存储。
// 存储的key
const getStorageKey = (name) => {
return "__recruit__" + name;
};
// 储存的对象
const getStorage = (storage) => {
return storage == "local" ? localStorage : sessionStorage;
};
// 初始化的state
export const getState = (name, storage, initialState) => {
return () => {
const data = getStorage(storage).getItem(getStorageKey(name));
return data ? JSON.parse(data) : initialState;
};
};
// 定义一个创建插件的函数
export default (modules) => {
// 获取需要存储的模块列表
const storageList = Object.entries(modules)
?.filter(([, module]) => module.meta?.storage)
?.map(([name, module]) => ({ name, storage: module.meta.storage }));
// 修改需要存储模块的state值
storageList?.forEach(({ name, storage }) => {
modules[name].state = getState(name, storage, modules[name].state);
});
return (store) => {
storageList?.forEach(({ name, storage }) => {
store.watch(
(state) => state[name],
(newValue) => {
getStorage(storage).setItem(getStorageKey(name), JSON.stringify(newValue));
},
{
immediate: true,
deep: true,
}
);
});
};
};
编写 store/index.js 文件
import Vue from "vue";
import vuex from "vuex";
import createStoragePlugin from "./plugins/storage";
Vue.use(vuex);
// 根据modules文件夹生成modules对象
const modulesFiles = require.context("./modules", true, /\.js$/);
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, "$1");
const value = modulesFiles(modulePath);
modules[moduleName] = value.default;
return modules;
}, {});
// 创建一个存储插件
const storagePlugin = createStoragePlugin(modules);
const store = new vuex.Store({
modules,
plugins: [storagePlugin],
});
export default store;
来看看效果吧