大改,使用pinia传值,indexdb做持久化
This commit is contained in:
1 parent
3ad7bae1a9
commit
9a045cfe86
20 files changed
+1527
-545
No files matched your search
@@ -0,0 +1,124 @@
|
||||
import type { PiniaPluginContext } from 'pinia'
|
||||
import localforage from 'localforage'
|
||||
|
||||
export type PersistOption = boolean | {
|
||||
key?: string
|
||||
debounce?: number
|
||||
}
|
||||
|
||||
type PersistStoreExt = {
|
||||
$persistNow?: () => Promise<void>
|
||||
$clearPersisted?: () => Promise<void>
|
||||
}
|
||||
|
||||
type PiniaStorageConfig = LocalForageOptions & {
|
||||
mode?: 'single' | 'multiple'
|
||||
debounce?: number
|
||||
}
|
||||
|
||||
const baseConfig: PiniaStorageConfig = {
|
||||
driver: localforage.INDEXEDDB,
|
||||
name: 'DB',
|
||||
version: 1,
|
||||
description: 'pinia persisted storage',
|
||||
storeName: 'pinia-storage',
|
||||
debounce: 300
|
||||
}
|
||||
|
||||
let singleStore: LocalForage | null = null
|
||||
const multipleStores = new Map<string, LocalForage>()
|
||||
|
||||
const getStore = (mode: 'single' | 'multiple', storeName: string, config: LocalForageOptions) => {
|
||||
if (mode === 'single') {
|
||||
if (!singleStore) {
|
||||
singleStore = localforage.createInstance({ ...baseConfig, ...config })
|
||||
}
|
||||
return singleStore
|
||||
}
|
||||
if (!multipleStores.has(storeName)) {
|
||||
multipleStores.set(
|
||||
storeName,
|
||||
localforage.createInstance({ ...baseConfig, ...config, storeName })
|
||||
)
|
||||
}
|
||||
return multipleStores.get(storeName) as LocalForage
|
||||
}
|
||||
|
||||
const resolvePersistOptions = (persist: PersistOption | undefined) => {
|
||||
if (!persist) return null
|
||||
if (persist === true) return {}
|
||||
return persist
|
||||
}
|
||||
|
||||
export default (config?: PiniaStorageConfig) => {
|
||||
const finalConfig = { ...baseConfig, ...(config || {}) }
|
||||
const { mode = 'single', debounce = 300, ...forageConfig } = finalConfig
|
||||
|
||||
return (context: PiniaPluginContext) => {
|
||||
const persistOptions = resolvePersistOptions(context.options.persist as PersistOption | undefined)
|
||||
if (!persistOptions) return
|
||||
|
||||
const storeId = context.store.$id
|
||||
const baseStoreName = forageConfig.storeName || baseConfig.storeName || 'pinia-storage'
|
||||
const resolvedStoreName = mode === 'multiple' ? `${baseStoreName}-${storeId}` : baseStoreName
|
||||
const key = persistOptions.key || (mode === 'single' ? `${baseStoreName}-${storeId}` : resolvedStoreName)
|
||||
const lf = getStore(mode, resolvedStoreName, forageConfig)
|
||||
const persistDebounce = persistOptions.debounce ?? debounce
|
||||
let timer: ReturnType<typeof setTimeout> | null = null
|
||||
let hydrating = false
|
||||
let userMutatedBeforeHydrate = false
|
||||
const writeState = (state: unknown) => lf.setItem(key, JSON.parse(JSON.stringify(state)))
|
||||
const storeExt = context.store as typeof context.store & PersistStoreExt
|
||||
|
||||
storeExt.$persistNow = async () => {
|
||||
if (timer) {
|
||||
clearTimeout(timer)
|
||||
timer = null
|
||||
}
|
||||
try {
|
||||
await writeState(context.store.$state)
|
||||
} catch (error) {
|
||||
console.error('pinia persist failed:', error)
|
||||
}
|
||||
}
|
||||
|
||||
storeExt.$clearPersisted = async () => {
|
||||
if (timer) {
|
||||
clearTimeout(timer)
|
||||
timer = null
|
||||
}
|
||||
try {
|
||||
await lf.removeItem(key)
|
||||
} catch (error) {
|
||||
console.error('pinia clear persisted failed:', error)
|
||||
}
|
||||
}
|
||||
|
||||
context.store.$subscribe(
|
||||
(_mutation, state) => {
|
||||
if (!hydrating) userMutatedBeforeHydrate = true
|
||||
if (timer) clearTimeout(timer)
|
||||
timer = setTimeout(() => {
|
||||
void writeState(state).catch(error => {
|
||||
console.error('pinia persist failed:', error)
|
||||
})
|
||||
}, Math.max(0, persistDebounce))
|
||||
},
|
||||
{ detached: true }
|
||||
)
|
||||
|
||||
void lf.getItem<Record<string, unknown>>(key)
|
||||
.then(state => {
|
||||
if (!state || typeof state !== 'object') return
|
||||
// 若在异步hydrate返回前,store已被用户修改(如removeTab),不再回填旧缓存覆盖当前状态。
|
||||
if (userMutatedBeforeHydrate) return
|
||||
hydrating = true
|
||||
context.store.$patch(state as any)
|
||||
hydrating = false
|
||||
})
|
||||
.catch(error => {
|
||||
hydrating = false
|
||||
console.error('pinia hydrate failed:', error)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user