前言
在Vue的日常的开发过程中,我们难免会使用上Vuex与浏览器的缓存,Vuex在每次页面重新页面后都会重新的加载Vuex里面的数据,一不小心就又回到了初始值。所以后面一个办法利用浏览器缓存将数据缓存起来。页面刷新的时候去检查缓存中是否存在如果存在就去缓存中的值。这就出现了一要更新Vuex中的值又要更新缓存中的值,久而久之觉得这种方法太麻烦了,需要我就去逛了逛了Vuex官网,发现一个重大的功能,Vuex是有拓展性的,可以自行添加插件功能
有了这个就好办了,可以将Vuex将浏览器缓存起来,将需要同时保存到缓存中的数据进行同步。 譬如像这样
这样上面的val表示的是vuex中的state数据,有user模块下的数据,key表示的是需要缓存道浏览器中的key值,type表示的是调用的store.commit
中的方法,其实dispatch
也是可以的,只有写对就行。
在完成上面的功能前,我们先将Cookies、localStorage、sessionStorage封装一下。 在封装的时候,加上前缀的,主要是看个人的需求吧。这里主要是项目名+版本号+key
cookies.js
import jsCookies from "js-cookie"
export class Cookies {
static prefix
static version
constructor(options) {
if (options && JSON.stringify(options) !== '{}') {
if (options.prefix) this.prefix = options.prefix
if (options.version) this.version = options.version
} else {
this.prefix =
import.meta.env.VITE_TITLE
this.version =
import.meta.env.VITE_VERSION
}
}
/**
* 存储 cookie 值
* @param name
* @param value
* @param cookieSetting
*/
set(name = "default", value = "", cookieSetting = {}) {
const currentCookieSetting = {
expires: 1,
path: import.meta.env.VITE_COOKIES_PATH,
domain: import.meta.env.VITE_COOKIES_DOMAIN,
...cookieSetting
};
jsCookies.set(
`${this.prefix}-${this.version}-${name}`,
value,
currentCookieSetting
);
}
/**
* 拿到 cookie 值
* @param name
* @returns
*/
get(name = "default") {
return jsCookies.get(
`${this.prefix}-${this.version}-${name}`
);
}
/**
* 拿到 cookie 全部的值
* @returns
*/
getAll() {
return jsCookies.get();
}
/**
* 删除 cookie
* @param name
*/
remove(name = "default", cookieSetting) {
// console.log("移除cookies",name)
const options = {
path: import.meta.env.VITE_COOKIES_PATH,
domain: import.meta.env.VITE_COOKIES_DOMAIN,
...cookieSetting
}
jsCookies.remove(
`${this.prefix}-${this.version}-${name}`, {
...options
}
);
}
/**
*
* @param {*} name key值
* @param {*} version 版本号
* @param {*} cookieSetting 多余的参数
* @param {*} prefix 前缀
*/
removeVersion(name = "default", version, prefix) {
const options = {
path: import.meta.env.VITE_COOKIES_PATH,
domain: import.meta.env.VITE_COOKIES_DOMAIN,
}
// console.log("移除removeVersion", name, version, options, `${prefix?prefix:this.prefix}-${version}-${name}`)
jsCookies.remove(
`${prefix?prefix:this.prefix}-${version}-${name}`, {
...options
}
);
}
removeAll(cookieSetting) {
var all = this.getAll()
const options = {
path: import.meta.env.VITE_COOKIES_PATH,
domain: import.meta.env.VITE_COOKIES_DOMAIN,
...cookieSetting
}
for (let i in all) {
jsCookies.remove(i,{...options});
}
}
}
export default new Cookies();
cache.js
class CommonLocalStorage {
constructor(storageModel) {
this.storage = storageModel;
this.prefix = import.meta.env.VITE_TITLE
this.version = import.meta.env.VITE_VERSION
}
setItem(key, value) {
// 执行监听的操作
return this.storage.setItem(`${this.prefix}-${this.version}-${key}`, value);
}
getItem(key) {
// 执行监听的操作
return this.storage.getItem(`${this.prefix}-${this.version}-${key}`);
}
removeItem(key) {
// 执行监听的操作
return this.storage.removeItem(`${this.prefix}-${this.version}-${key}`);
}
removeVersion(key,version,prefix) {
// 执行监听的操作
return this.storage.removeItem(`${prefix?prefix:this.prefix}-${version}-${key}`);
}
clear() {
// 执行监听的操作
this.storage.clear();
}
}
export const storageSession = new CommonLocalStorage(sessionStorage);
export const storageLocal = new CommonLocalStorage(localStorage);
checkFailureCacheAndCookies.js
在我们修改版本号或者是项目名的时候,我们就需要将原先的缓存清除掉。不然日积月累的情况下,很容易的就会满的,比较容量是有限的。
这个只在放在入口文件中引用即可
import * as storage from "@/utils/cache"
import {
Cookies
} from "@/utils/cookies"
/**
*
* @param {*} version 版本号
* @param {*} prefix 前缀
* @param {*} type 类型:cookies、storageLocal、storageSession
*/
function checkFailureCacheAndCookies(options) {
let type = ["cookies", "storageLocal", "storageSession"]
options = {
version: import.meta.env.VITE_VERSION,
prefix: import.meta.env.VITE_TITLE,
...options
}
//校验key名的白名单
let storageWhiteList = ["length", "clear", "getItem", "key", "removeItem", "setItem"]
function clear(data, storage, type) {
for (let i in data) {
if (options.oldPrefix && options.oldPrefix !== options.prefix) {
//不同前缀,不管版本号,直接删除旧的
let keyArr = i.split(options.oldPrefix)
if (keyArr.length <= 1) return
keyArr = keyArr[1].split("-")
storage.removeVersion(keyArr[2], keyArr[1], options.oldPrefix)
} else {
if (type == "storage" && storageWhiteList.includes(i)) return
//同个前缀检查版本号,不一致就删除不同版本号的
let keyArr = i.split(options.prefix)
// console.log(options.prefix,keyArr,keyArr.length <= 1)
if (keyArr.length <= 1) return
keyArr = keyArr[1].split("-")
// console.log(keyArr,options.version,keyArr[1] !== options.version)
if (keyArr[1] !== options.version) {
storage.removeVersion(keyArr[2], keyArr[1])
}
}
}
}
//用于清除其他中台的cookies缓冲
if (options.type === "cookies") {
const cookies = new Cookies()
let data = cookies.getAll()
clear(data, cookies, "cookies")
} else {
for (let t of type) {
if (t === 'cookies') {
const cookies = new Cookies()
let data = cookies.getAll()
clear(data, cookies, "cookies")
} else {
let data = storage[t].storage
clear(data, storage[t], "storage")
}
}
}
}
// checkFailureCacheAndCookies()
export default checkFailureCacheAndCookies
封装完我们的浏览器缓存部分,就开始来封装我们的插件功能,这里仅是封装了读取或者获取的功能,有想要其他的功能拓展的可以自行拓展。
persistedstate.js
import {
storageSession,
storageLocal
} from "@/utils/cache"
export default function persistedstate(options) {
options = options || {};
const storage = options.storage || storageLocal;
const key = options.key;
if(!key){
throw new Error("请先添加key")
}
if(!options.type){
throw new Error("请先添加mutation中的type")
}
function getState(key, storage) {
const value = storage.getItem(key);
try {
return (typeof value === "string") ?
JSON.parse(value) : (typeof value === "object") ?
value : undefined;
} catch (err) {}
return undefined;
}
function setState(key, state, storage) {
// return storage.setItem(key, JSON.stringify(state));
state = JSON.stringify(state)
// console.log("设置时候的key",key,state,state=='""',state == "{}",state == "[]")
if(state && state !== "{}" && state !== "[]" && state !== '""'){
return storage.setItem(key, state);
}else{
removeState(key)
}
}
function reducer(state, mutation) {
return state;
}
function subscriber(store) {
return function (handler) {
return store.subscribe(handler);
};
}
function removeState(key){
// if(storage.isCookies){
// // console.log("移除的key",key,storage)
// storage.removeItem(key,{path:import.meta.env.VITE_COOKIES_PATH,domain:import.meta.env.VITE_COOKIES_DOMAIN});
// }else{
// storage.removeItem(key);
// }
storage.removeItem(key);
}
const assertStorage =
options.assertStorage ||
(() => {
storage.setItem("@@", 1);
removeState("@@")
});
assertStorage(storage);
const fetchSavedState = () => (options.getState || getState)(key, storage);
let savedState;
if (options.fetchBeforeUse) {
savedState = fetchSavedState();
}
return function (store) {
if (!options.fetchBeforeUse) {
savedState = fetchSavedState();
}
// console.log("vuex插件初始化", store,savedState);
store.commit(options.type, savedState);
(options.subscriber || subscriber)(store)(function (mutation, state) {
if(options.type === mutation.type){
// console.log(state,mutation);
(options.setState || setState)(
key,
(options.reducer || reducer)(state,mutation),
storage
);
}
});
};
}
应用插件功能
///dataPlugins.js
import persistedstate from "@/utils/persistedstate"
import Cookies from '@/utils/cookies';
const cookies = {
getItem: (key) => Cookies.get(key),
setItem: (key, value, options) => Cookies.set(key, value, {
path:import.meta.env.VITE_COOKIES_PATH,
domain: import.meta.env.VITE_COOKIES_DOMAIN,
...options
}),
removeItem: (key, options) => Cookies.remove(key, {
path:import.meta.env.VITE_COOKIES_PATH,
domain: import.meta.env.VITE_COOKIES_DOMAIN,
...options
}),
// isCookies:true
}
const dataPlugins = [
persistedstate({
key: "userInfo",
type: "user/setUserInfo",
reducer(val) { // 注意: 指定需要持久化的数据
// console.log('userInfo', val)
return val.user.userInfo
}
}),
persistedstate({
key: "userId",
type: "user/setUserId",
reducer(val) { // 注意: 指定需要持久化的数据
// console.log('userInfo', val)
return val.user.userId
},
storage: {
...cookies
}
}),
]
///store/index.js
import dataPlugins from "./dataPlugins"
const store = new createStore({
plugins: dataPlugins
});
export default store;
其中这个storage缓存的对象也是可以自定义的。
总结
革命尚未成功,还需努力。
需要拓展的功能的,有兴趣可以自己研究一下。