pinia使用插件化开发(uniapp中使用持久化)

733 阅读5分钟

简介

本文将介绍如何使用 Pinia 插件来实现 Vue 应用中状态管理的本地存储功能。我们将展示如何定义一个 Pinia 插件,以及如何将该插件与您的 Vue 应用中的状态管理结合起来。我们还将展示如何编写一个自定义的本地存储插件,以实现同步和异步的本地存储功能。

Pinia 插件定义

首先,我们需要定义一个 Pinia 插件。在这个插件中,我们将定义一个名为 persitslocalStorge 的选项,该选项包含以下属性:

  • enble:布尔值,表示是否启用本地存储功能。
  • locState:函数,接收一个包含所有状态属性的对象作为参数,返回一个数组,表示需要缓存的状态属性。
  • locStateOptions:字符串,表示本地存储类型,可以是 localStoragesessionStorage
  • asynclocal:布尔值,表示是否启用异步本地存储,默认为同步缓存。
interface perPlugin<S>
{ 
    enble?:boolean, 
    locState?:locCallback<S>, 
    locStateOptions?:localOptions,
    asynclocal?:boolean 
}

接下来,我们需要扩展 pinia 模块,以便在 DefineStoreOptionsInPluginDefineStoreOptions 中包含我们定义的 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 应用中状态管理的本地存储功能。这个插件允许我们根据需要自定义缓存的状态属性,以及选择同步或异步的本地存储方式。