vue3-persist-storages
v1.0.3
Published
vue3的本地存储最全方案,集成了cookie、localStorage、sessionStorage、indexedDB、webSQL等所有前端数据存储的方式,也赋予 pinia 持久化的能力
Downloads
33
Maintainers
Readme
vue3-persist-storages
前言
众所周知,前端的存储方案主要是以下几种组成:
- Cookies
- LocalStorage、SessionStorage
- indexedDB
- Web SQL
- SQLite(小型数据库)
它们之间各自有相应的API,存在差异性比较大,在实际业务开发中,几乎有可能几种存储方案都会使用,他们各自有各自的优缺点,想要进一步了解的,请参考文章:数据持久化存储方案,这里不做过多赘叙,在相同的产品中,对每个持久化存储的方式都有相同需求,于是就有了vue3-persist-storages
的出现,目标是就是创造相同api,封装相同的功能,兼容各种实际场景,抹平不同存储的差异化调用。
特点
- ✅ 囊括了
Cookies
、LocalStorage
、SessionStorage
、indexedDB
、WebSQL
所有存储方案,可以自定义选择 - ✅ 支持普通对象和
代理对象proxy
的存储 - ✅ 支持本地持久化存储的
有效期设置
- ✅ 支持通过配置
前缀、后缀
,防止父子项目之间持久化数据互相污染 - ✅ 支持本地存储的数据自定义配置
AES加密
和解密
- ✅ 封装了pinia plugin 插件,支持pinia 的持久化存储,具体特点如下:
- 与 vuex-persistedstate 相似的 API
- 所有 Store 均可单独配置,也可以全局设置
- 恢复持久化数据前后的 hook
- 同样支持
有效期
、数据加密和解密
、自定义storage
设置
安装
// npm
npm i vue3-persist-storages
// yarn
yarn add vue3-persist-storages
// pnpm
pnpm i vue3-persist-storages
使用Cookies
cookies的存储主要采用js-cookie作为解决方案
CreateCookies API
export declare class CreateCookies {
/** 前缀,会自动加到 key 值的前面,默认值:'' */
private prefix;
/** 后缀,会自动加到 key 值的后面,默认值:''*/
private suffix;
/** 是否开启有效期设置,默认值:false */
private isOpenExpires;
/** 有效期设置,和isOpenExpires配搭使用,单位:天, 默认值:7 天 */
private day;
/** 是否开启AES加密和解密数据, 默认值:false */
private encryption;
/** 加密时需要的密钥,自动生成,不需要设置 */
private encryptionKey;
constructor(option?: IStorageOption);
/**
* @description 设置cookie
* @param {string} name cookie 名称
* @param {any} value cookie 值
* @param {number} expire 过期时间, 单位:day
* @param {boolean} isOpen 是否打开过期时间的设置
*/
setItem(key: string, value: any, expires?: number | null, isOpen?: boolean | null): void;
/**
* 根据名字获取cookie值
* @description Cookies.get()取不到值的时候会返回空字符串 ’‘
* @param name 键名
*/
getItem(key: string): string;
/**
* 根据名字删除指定的cookie
* 注意,删除不存在的cookie不会报错也不会有返回
* @param key
*/
removeItem(key: string): void;
}
CreateCookies 基本用法
import { CreateCookies } from 'vue3-persist-storages'
const cookies = new CreateCookies()
// 普通使用 string/boolean/number 基本类型
cookies.setItem('name', '张三')
console.log(cookies.getItem('name')) // 输出 张三
// 保存对象,直接传入即可
cookies.setItem('name', {id: '张三'})
// 可以开启有效期、数据加密、前后缀防止数据污染
const cookies = new CreateCookies({
prefix: '前缀',
suffix: '后缀',
isOpenExpires: true,
day: 0.5,
encryption: false,
})
使用Storage
Storage 分为LocalStorage、SessionStorage,两者的api完全一样,可以直接使用
CreateStorage API
import { IStorageOption } from './types';
export declare class CreateStorage {
/** 默认值: localStorage*/
private storage;
/** 前缀,会自动加到 key 值的前面,默认值:'' */
private prefix;
/** 后缀,会自动加到 key 值的后面,默认值:''*/
private suffix;
/** 是否开启有效期设置,默认值:false */
private isOpenExpires;
/** 有效期设置,和isOpenExpires配搭使用,单位:天, 默认值:7 天 */
private day;
/** 是否开启AES加密和解密数据, 默认值:false */
private encryption;
/** 加密时需要的密钥,自动生成,不需要设置 */
private encryptionKey;
constructor(option?: IStorageOption);
/**
* @description 设置缓存
* @param key 缓存键
* @param value 缓存值
* @param expires 到期时间
* @param isOpen 是否开启到期时间的计算
*/
setItem(key: string, value: any, expires?: number | null, isOpen?: boolean | null): void;
/**
* @description 读取缓存
* @param {string} key 缓存键
* @param {any} def 默认值,不传的话默认值为null
* @returns 返回缓存值,如果超出有效期,则返回null或者用户自定义的默认值
*/
getItem(key: string, def?: any): any;
/**
* @description 从缓存删除某项
* @param {string} key 缓存键
*/
removeItem(key: string): void;
/**
* @description 清空所有缓存
*/
clear(): void;
}
export default CreateStorage;
CreateStorage 基本用法
基本使用和cookie的方法一样,
CreateStorage
只是多了一个storage
属性,可以供开发选择sessionStorage
还是localStorage
的存储方式
import { CreateStorage } from 'vue3-persist-storages'
const storage = new CreateStorage()
// 普通使用 string/boolean/number 基本类型
storage.setItem('name', '张三')
console.log(storage.getItem('name')) // 输出 张三
// 保存对象,直接传入即可
storage.setItem('name', {id: '张三'})
// 可以开启有效期、数据加密、前后缀防止数据污染
const storage = new CreateCookies({
storage: sessionStorage,
prefix: '前缀',
suffix: '后缀',
isOpenExpires: true,
storage: ,
day: 0.5,
encryption: false,
})
使用indexedDB
indexedDB的API相对更难一些,为了更方便使用和入门,vue3PersistStorages采取了localForage作为接入indexedDB
的解决方案,localForage
只需要通过简单类似 localStorage API
的异步存储来改进你的 Web 应用程序的离线体验,它能存储多种类型的数据,而不仅仅是字符串,针对浏览器进行了兼容处理,当浏览器无法兼容indexedDB
会自动降级使用localStorage
进行存储。它还有一个优势,就是后续可以拓展方法与sqlite
进行联动使用。
CreateLocalForage API
import { IStorageOption } from './types';
export declare class CreateLocalForage {
private storage;
private config;
private lcalForageConfig;
private waitQueues;
private debug;
private encryption;
private encryptionKey;
constructor(option?: IStorageOption & LocalForageOptions);
/**
* 初始化存储对象
*/
init(): void;
/**
* @description 读取数据库数据
* @param key 缓存键值
* @param def 默认值,不传的话默认值为null
* @returns 本地有数据就那本地数据,没数据就返回默认值
*/
getItem(key: string, def?: any): Promise<any>;
/**
* @description 设置缓存数据
* @param key 缓存键
* @param value 缓存值,
* @member value的类型 支持以下类型
* Array
ArrayBuffer
Blob
Float32Array
Float64Array
Int8Array
Int16Array
Int32Array
Number
Object
Uint8Array
Uint8ClampedArray
Uint16Array
Uint32Array
String
*/
setItem(key: string, value: any, _isOpenExpires?: boolean | undefined, expires?: number | undefined): Promise<any>;
/**
* @description 从缓存删除某项
* @param {string} key 缓存键
*/
removeItem(key: string): Promise<unknown>;
/**
* @description 清空所有缓存
*/
clear(): Promise<unknown>;
/**
* 获取本地数据库的大小,主要是获取indexDB的大小
* {
quota: 440922000000, // 最大可用字节数, 浏览器存储空间配额
usage: 27300000, // 已用字节数, 浏览器已经使用的存储空间大小,
usageDetails: { // 这个返回结果不固定
indexedDB: 676000, // indexedDB的使用占用空间的大小情况,单位字节,
cacheapi: 26500000, // 缓存空间
serviceworker: 52800 // serviceworker服务
}
} */
getSize(): Promise<string | null>;
}
export default CreateLocalForage;
LocalForageOptions 属性
如果你想单纯只使用LocalForage API
的话,可以只配置LocalForageOptions
属性,即可跟官方配置一样
| 属性名 | 类型 | 说明 |默认值 | | ------- | ------- | --------- | --------- | | driver | string | string[] | 驱动,也就是选择是存储方式 | [localforage.INDEXEDDB, localforage.WEBSQL,localforage.LOCALSTORAGE] | | size | string | 数据库的大小(以字节为单位)。目前仅在 WebSQL 中使用 | - | | version | string | 数据库的架构版本。仅在 WebSQL 和 IndexedDB 中使用 | - | | description | string | 数据库的描述,主要供开发人员使用 | - | | name | string | 数据库的名称 | Vue3PersistStorage | | storeName | string | 数据库建表的名称 | DataSheet |
IStorageOption 属性
如果在希望给LocalForage
的使用上,加上有效期设置
、数据加密解密功能
、添加前缀后缀
防止数据污染,则需要额外添加IStorageOption
属性
export interface IPluginOption {
// 前缀, 默认值: ""
prefix?: string;
// 后缀 默认值: ""
suffix?: string;
// 数据库名称, 默认值:Vue3PersistStorage
name?: string;
// 数据库中表名,默认值:DataShee
storeName?: string;
// 调试模式,还原失败打印报错(可选)
debug?: boolean;
// 是否开启加密功能
encryption?: boolean
}
export interface IStorageOption extends IPluginOption {
// 是否开启有效期, 默认值:false
isOpenExpires?: boolean;
// 有效期默认几天, 默认值: 7天
day?: number;
}
CreateLocalForage 使用
import { CreateLocalForage } from 'vue3-persist-storages'
// 直接使用localforage的api和相关方法
const localforage = new CreateLocalForage({
name:'test',
storeName: 'sheet',
driver: [localforage.LOCALSTORAGE],
})
// 生成的localforage对象,会直接存放在`CreateLocalForage`的storages属性中,这样可以随时调用,CreateLocalForage没有封装过的关于localforage api的方法,
// 关于localforage更具体的api,可以参考: https://localforage.docschina.org/
localforage.storage.keys((key: any) => { console.log(key); })
// 可以开启有效期、数据加密、前后缀防止数据污染
const localforage = new CreateLocalForage({
prefix: '前缀',
suffix: '后缀',
storage: localStorage,
isOpenExpires: true,
day: 0.5,
encryption: false,
})
localforage.setItem('name', { id: 1 })
console.log(localforage.getItem('name'))
// 可以为单个键值为name,独立设置数据有效期为0.5天,其他数据不设有效期
localforage.setItem('name', { id: 1 }, true, 0.5)
使用Pinia Plugin 持久化存储
市场上pinia常用的持久化存储方案主要有以下两种:
以上两种方案在实际使用过程中,都发现以下不足:
- 不支持配置前缀后缀
- 不支持indexedDB,可能indexedDB是异步储存
- 不支持配置数据有效期
- 不支持配置数据加密和解密
于是才有了vue3-persist-storages
,这里的Pinia Plugin
是基于CreateLocalForage、CreateCookies、CreateStorage
等三种方法而集成使用的。
初始化
// 直接配置插件
import { createPinia } from 'pinia'
import piniaPluginPersisted from 'vue3-persist-storages'
const pinia = createPinia()
pinia.use(piniaPluginPersisted)
全局配置
如果你不想要同域名下子项目持久化数据之间互相污染,可以全局配置前缀或后缀、数据库名、表名、是否开启调试、是否开启加密
export interface IPluginOption {
// 前缀, 默认值: ""
prefix?: string;
// 后缀 默认值: ""
suffix?: string;
// 数据库名称, 默认值:Vue3PersistStorage
name?: string;
// 数据库中表名,默认值:DataShee
storeName?: string;
// 调试模式,还原失败打印报错(可选)
debug?: boolean;
// 是否开启加密功能
encryption?: boolean
}
具体使用:
import { createPinia } from 'pinia'
import {createPlugin} from 'vue3-persist-storages'
const pinia = createPinia()
pinia.use(createPlugin({
// 前缀
prefix: '子项目id',
// 开启数据加密
encryption: true,
// 开启调试
debug: true
// 全局配置默认数据库名
name: 'TestDataBase'
}))
模块配置
模块想要启用持久化,可以配置 persist 参数,它的类型是 TPersist
// 全局的配置,单个模块也可以继承,重新配置
export interface IPluginOption {
// 前缀, 默认值: ""
prefix?: string;
// 后缀 默认值: ""
suffix?: string;
// 数据库名称, 默认值:Vue3PersistStorage
name?: string;
// 数据库中表名,默认值:DataShee
storeName?: string;
// 调试模式,还原失败打印报错(可选)
debug?: boolean;
// 是否开启加密功能
encryption?: boolean
}
export interface IStorageOption extends IPluginOption {
// storage类型,有localStorage、sessionStroage(可选),可配合type使用
storage?: Storage;
// 是否开启有效期, 默认值:false
isOpenExpires?: boolean;
// 有效期默认几天, 默认值: 7天
day?: number;
}
export interface PersistOptions extends IStorageOption {
// 使用 indexedDB 或 storage(可选)
type?: 'storage' | 'indexedDB' | 'cookies';
// 持久化存储的key(可选)
key?: string;
// 需要持久化的数据的路径(可选)
paths?: string[];
// 还原前执行函数(可选)
beforeRestore?: (context: PiniaPluginContext) => void;
// 还原后执行函数(可选)
afterRestore?: (context: PiniaPluginContext) => void;
}
export type TPersist = boolean | PersistOptions | PersistOptions[];
当你要启用持久化时,可以这么做
export const useUserStore = defineStore({
id: 'user',
persist: true, // 开启持久化
state: () => ({
name: 'caoguanjie'
})
});
当你设置 persist = true 时,此模块开启了持久化功能,相当于传入了默认配置:
persist: {
type: 'indexedDB',
name: 'Vue3PersistStorage'
storeName: 'DataSheet'
key: $store.id, // 此模块的默认id
paths: undefined,
encryption: false,
beforeRestore: undefined,
afterRestore: undefined,
debug: false,
}
当然,你也可以传入persist
相关对象属性,进行配置,如下:
export const useUserStore = defineStore({
id: 'user',
persist: {
type: 'indexedDB',
name: 'TestDataBase'
storeName: 'DataSheet'
key: 'customKey', // 自定义id,不传就是默认模块id
paths: ['name'],
encryption: true,
beforeRestore: () =>{
console.log('beforeRestore');
},
afterRestore: () => {
console.log('afterRestore');
},
debug: false
}, // 开启持久化
state: () => ({
name: 'caoguanjie'
})
});
如果遇到模块不同的变量需要用不同的存储方式时,你也可以传入数组
结构的数据,如下方法:
persist: [
{
type: 'indexedDB',
encryption: true, // 用户信息可以设置加密
paths: ["userInfo", "isRememberme", "loginInfo"],
},
{
key: 'accessToken',
type: 'cookies', // token可以cookies保存,并且可以自定义设置键名为accessToken
paths: ["token"],
},
],
实现自定义存储方式
当使用pinia持久化时,发现以上所有存储方式都无法不合适时,你可以采取自定义的方式,定制数据的提取和存储,例如,要独立实现token字段存储,可以通过以下配置:
persist: [
{
type: 'indexedDB',
encryption: true, // 用户信息可以设置加密
paths: ["userInfo", "isRememberme", "loginInfo"],
},
{
key: 'accessToken',
type: 'custom', // token可以js-cookies保存,并且可以自定义设置键名为accessToken
paths: ["token"],
// storage的格式一定要按这个模式写setItem、getItem函数
storage: {
setItem(key: string, state: any) {
// 默认有效期是7天
const _state = JSON.parse(state);
return Cookies.set("accessToken", _state.token);
},
getItem(key: string) {
return JSON.stringify({
token: Cookies.get("accessToken"),
});
},
}
},
],
已知的问题
- 使用CreateLocalForage、CreateCookies、CreateStorage中的
setItem
方法,支持单独为某个键值的存储数据,设置有效时间,但是无法为单个数据设置加密和解密。 - pinia的
store.$subscribe
方法是监控所有模块的对象数据变化的,因此当数据量大的时候,复杂对象的监控会极其消耗性能,甚至造成卡顿的情况,在实际场景中,发现使用indexedDB存储数据超过100MB的时候,每次数据的保存,都会有卡顿的情况。性能差的电脑和手机端尤为明显。 - 为了兼容pinia的
Options API
和Composition API
两种写法产生的对象不同,Vue3PersistStorage
用了JSON.stringify
序列化和JSON.parse
反序列化来处理对象,在一定程度上会造成多余的性能开销 Vue3PersistStorage
不支持vue2
和SSR