简介
本文将介绍如何使用 Pinia 插件来实现 Vue 应用中状态管理的本地存储功能。我们将展示如何定义一个 Pinia 插件,以及如何将该插件与您的 Vue 应用中的状态管理结合起来。我们还将展示如何编写一个自定义的本地存储插件,以实现同步和异步的本地存储功能。
Pinia 插件定义
首先,我们需要定义一个 Pinia 插件。在这个插件中,我们将定义一个名为 persitslocalStorge 的选项,该选项包含以下属性:
enble:布尔值,表示是否启用本地存储功能。locState:函数,接收一个包含所有状态属性的对象作为参数,返回一个数组,表示需要缓存的状态属性。locStateOptions:字符串,表示本地存储类型,可以是localStorage或sessionStorage。asynclocal:布尔值,表示是否启用异步本地存储,默认为同步缓存。
interface perPlugin<S>
{
enble?:boolean,
locState?:locCallback<S>,
locStateOptions?:localOptions,
asynclocal?:boolean
}
接下来,我们需要扩展 pinia 模块,以便在 DefineStoreOptionsInPlugin 和 DefineStoreOptions 中包含我们定义的 persitslocalStorge 选项:
declare module 'pinia' {
interface DefineStoreOptionsInPlugin< Id extends string, S extends StateTree, G, A >
{ persitslocalStorge?: perPlugin<S>; }
interface DefineStoreOptions< Id extends string, S extends StateTree, G, A >
{ persitslocalStorge?: perPlugin<S>; } }
Store 定义
在您的 Vue 应用中,定义一个使用 persitslocalStorge 选项的 Pinia store:
export default defineStore(
{ id: "user",
state: () =>
{
return { token: "1", uname: "", uavatar: {} } as User._user
},
getters: {
msg:(state)=>{ return state }
},
actions: {
getUsertoken(data:_data.data<User._user>){ // ... }
},
persitslocalStorge:{
enble:true,
locState:(state)=>{
console.log(state?.token,Object.keys(state)); return ['token','uname']
},
locStateOptions:'localStorage' }
}
)
编写本地存储插件
接下来,我们将编写一个名为 persistentPlugin 的插件函数,该函数接收一个 PiniaPluginContext 对象作为参数。在该函数中,我们将根据 persitslocalStorge 选项的设置,执行同步或异步的本地存储操作。
export default function persistentPlugin(context: PiniaPluginContext) {
const{ store, options } = context;
const { persitslocalStorge } = options as { persitslocalStorge: PersitsLocalStorgeOptions };
// 如果 persitslocalStorge 启用,则获取选定的变量并调用 enabledbol 函数 if (persitslocalStorge && persitslocalStorge.enble) {
const theSelectedVariables = persitslocalStorge.locState?.(store.$state);
enabledbol(store, persitslocalStorge.asynclocal, theSelectedVariables);
store.$subscribe((mutation, state) => {
enabledbol(store, persitslocalStorge.asynclocal, theSelectedVariables);
}); } }
在 persistentPlugin 函数中,我们首先检查 persitslocalStorge 选项是否启用。如果启用,我们将获取需要缓存的状态属性,并调用 enabledbol 函数执行本地存储操作。此外,我们还需要监听 store 的变化,以便在状态发生变化时更新本地存储。 接下来,我们将实现 enabledbol 函数。该函数根据给定的 locState 数组,执行同步或异步存储操作:
function enabledbol(store: Store, asyncBol: boolean | undefined, locState: ArrType | undefined): void
{
if (locState)
{
const stateKeys = Object.keys(store.$state) as StateKeyType[];
const stateSubset = getStateSubset(stateKeys, locState, store.$state);
if (stateSubset) {
try { asyncBol ? localAsyncStorageState(stateSubset) : localStorageState(stateSubset);
} catch (error) {
//这里之后调用全局提示错误
}
}
}
}
我们还需要实现 getStateSubset 函数,用于从 state 对象中获取 locState 数组所指定的子集:
function getStateSubset(arr: ArrType, prpArr: ArrType, state: StateTree): Record<StateKeyType, any> | null
{ const set2 = new Set<StateKeyType>(arr);
const isSubset = array1IsSubsetOfArray2(prpArr, set2); console.log(isSubset);
if(isSubset)
{
const result: Record<StateKeyType, any> = {};
for (const key of prpArr) { result[key] = state[key]; }
console.log(result);
return result;
}
return null;
}
最后,我们需要实现同步和异步存储操作。对于同步操作,我们将使用 localStorageState 函数将 state 对象的子集存储到本地存储中;对于异步操作,我们将使用 localAsyncStorageState 函数将 state 对象的子集存储到本地存储中:
function localStorageState(stateObj: Record<StateKeyType, any>): void {
for (const key in stateObj)
{ uni.setStorageSync(key, stateObj[key]);
}
}
function localAsyncStorageState(data: Record<StateKeyType, any>): void
{
for (const key in data)
{ uni.setStorage({
key,
data: data[key],
fail:(e)=>{ throw new Error("请重新连接异步数据!"); } });
}
}
最后我们在index.ts中添加插件对象把对象导出给外层index
import persistentPlugin from './localpersits'
import { PiniaPluginContext } from 'pinia';
interface LocalPers{
[propname: string]:(context:PiniaPluginContext)=>void
}
const components: LocalPers = {
persistentPlugin
};
export default components
最后导出store实例
import piniaPluginStore from './plugin/index'
const store = createPinia()
for (const key in piniaPluginStore) {
store.use(piniaPluginStore[key])
}
export default store
import { PiniaPluginContext,DefineStoreOptionsInPlugin,StateTree,DefineStoreOptions,StoreState,Store,PiniaCustomStateProperties } from 'pinia';
type StoreWithState<S> = {
[propName in keyof S]:S[propName]
}
type localOptions = 'localStorage'|'sessionStorage'
type locCallback<S> = (locState: StoreWithState<S>) => Array<string|keyof StoreWithState<S>>;
/**
* @enble (是否开启缓存)
* @locState (字符数组进行缓存标注,可获取statekey执行全部缓存)
* @locStateOptions (缓存类型)
* @asynclocal (是否开启异步缓存,默认同步缓存)
*/
interface perPlugin<S>{
enble?:boolean,
locState?:locCallback<S>,
locStateOptions?:localOptions,
asynclocal?:boolean
}
declare module 'pinia' {
interface DefineStoreOptionsInPlugin<
Id extends string,
S extends StateTree,
G,
A
> {
persitslocalStorge?: perPlugin<S>;
}
interface DefineStoreOptions<
Id extends string,
S extends StateTree,
G,
A
>{
persitslocalStorge?: perPlugin<S>;
}
type StoreWithState<S> = {
[propName in keyof S]:S[propName]
}
type locCallback<S> = (locState: StoreWithState<S>) => Array<string|keyof StoreWithState<S>>;
}
import { PiniaPluginContext, Store, StateTree } from 'pinia';
type ArrType = Array<string | number | symbol>;
type StateKeyType = string | number | symbol;
// 定义 persitslocalStorge 选项的接口
interface PersitsLocalStorgeOptions {
enble?: boolean;
asynclocal?: boolean;
locState?: (state: StateTree) => ArrType;
}
// 主插件函数
export default function persistentPlugin(context: PiniaPluginContext) {
const { store, options } = context;
const { persitslocalStorge } = options as { persitslocalStorge: PersitsLocalStorgeOptions };
// 如果 persitslocalStorge 启用,则获取选定的变量并调用 enabledbol 函数
if (persitslocalStorge && persitslocalStorge.enble) {
const theSelectedVariables = persitslocalStorge.locState?.(store.$state);
enabledbol(store, persitslocalStorge.asynclocal, theSelectedVariables);
store.$subscribe((mutation, state) => {
enabledbol(store, persitslocalStorge.asynclocal, theSelectedVariables);
});
}
}
// 根据给定的 locState 数组,执行同步或异步存储操作
function enabledbol(store: Store, asyncBol: boolean | undefined, locState: ArrType | undefined): void {
if (locState) {
const stateKeys = Object.keys(store.$state) as StateKeyType[];
const stateSubset = getStateSubset(stateKeys, locState, store.$state);
if (stateSubset) {
try {
asyncBol ? localAsyncStorageState(stateSubset) : localStorageState(stateSubset);
} catch (error) {
//这里之后调用全局提示错误
}
}
}
}
// 从 state 对象中获取 locState 数组所指定的子集
function getStateSubset(arr: ArrType, prpArr: ArrType, state: StateTree): Record<StateKeyType, any> | null {
const set2 = new Set<StateKeyType>(arr);
const isSubset = array1IsSubsetOfArray2(prpArr, set2);
console.log(isSubset);
if (isSubset) {
const result: Record<StateKeyType, any> = {};
for (const key of prpArr) {
result[key] = state[key];
}
console.log(result);
return result;
}
return null;
}
// 检查 array1 是否为 array2 的子集
function array1IsSubsetOfArray2(array1: ArrType, set2: Set<StateKeyType>): boolean {
console.log(array1,set2);
return array1.every((item) => set2.has(item));
}
// 将 state 对象的子集存储到本地存储(同步)
function localStorageState(stateObj: Record<StateKeyType, any>): void {
for (const key in stateObj) {
uni.setStorageSync(key, stateObj[key]);
}
}
// 将 state 对象的子集存储到本地存储(异步)
function localAsyncStorageState(data: Record<StateKeyType, any>): void {
for (const key in data) {
uni.setStorage({
key,
data: data[key],
fail:(e)=>{
throw new Error("请重新连接异步数据!");
}
});
}
}
总结
通过以上步骤,我们已经实现了一个名为 persistentPlugin 的 Pinia 插件,用于实现 Vue 应用中状态管理的本地存储功能。这个插件允许我们根据需要自定义缓存的状态属性,以及选择同步或异步的本地存储方式。