useStorage
创建一个响应式的 ref,它可用于访问和修改 LocalStorage 或 SessionStorage。默认使用 LocalStorage,其他存储源可通过第三个参数指定。
Demo
<script setup lang="ts">
import { reactify, useStorage } from '@vueuse/core'
import YAML from 'yaml'
const stringify = reactify(
(input: any) => YAML.stringify(input, (k, v) => {
if (typeof v === 'function') {
return undefined
}
return v
}, {
singleQuote: true,
flowCollectionPadding: false,
}),
)
const theDefault = {
name: 'Banana',
color: 'Yellow',
size: 'Medium',
count: 0,
}
const state = useStorage('vue-use-local-storage', theDefault)
const state2 = useStorage('vue-use-local-storage', theDefault)
const text = stringify(state2)
</script>
<template>
<div>
<input v-model="state.name" type="text">
<input v-model="state.color" type="text">
<input v-model="state.size" type="text">
<input v-model.number="state.count" type="range" min="0" step="0.01" max="1000">
<pre lang="json">{{ text }}</pre>
</div>
</template>
使用
在使用 Nuxt 3 时,此函数不会被自动导入,因为 Nitro 内置了
useStorage()。如果你想使用 VueUse 中的此函数,请进行显式导入。import { useStorage } from '@vueuse/core'
// bind object
const state = useStorage('my-store', { hello: 'hi', greeting: 'Hello' })
// bind boolean
const flag = useStorage('my-flag', true) // returns Ref<boolean>
// bind number
const count = useStorage('my-count', 0) // returns Ref<number>
// bind string with SessionStorage
const id = useStorage('my-id', 'some-string-id', sessionStorage) // returns Ref<string>
// delete data from storage
state.value = null
合并默认值
useStorage 默认情况下会使用存储中的值(如果存在),并会忽略你提供的默认值。请注意,如果你在默认值中添加了新的属性,而客户端的存储中没有对应的键,那么该属性的值可能会是 undefined。
localStorage.setItem('my-store', '{"hello": "hello"}')
const state = useStorage('my-store', { hello: 'hi', greeting: 'hello' }, localStorage)
console.log(state.value.greeting) // undefined, since the value is not presented in storage
要解决这个问题,你可以启用 mergeDefaults 选项。
localStorage.setItem('my-store', '{"hello": "nihao"}')
const state = useStorage(
'my-store',
{ hello: 'hi', greeting: 'hello' },
localStorage,
{ mergeDefaults: true } // <--
)
console.log(state.value.hello) // 'nihao', from storage
console.log(state.value.greeting) // 'hello', from merged default value
当将它设置为 true 时,它会对对象执行浅合并(shallow merge)。你可以传入一个函数来执行自定义合并(例如,深合并),例如:
const state = useStorage(
'my-store',
{ hello: 'hi', greeting: 'hello' },
localStorage,
{ mergeDefaults: (storageValue, defaults) => deepMerge(defaults, storageValue) } // <--
)
自定义序列化
useStorage 默认会根据所提供默认值的数据类型智能地选择相应的序列化器。例如,对于对象,它会使用 JSON.stringify / JSON.parse;对于数字,会使用 Number.toString / parseFloat 等。
你也可以向 useStorage 提供你自己的序列化函数:
import { useStorage } from '@vueuse/core'
useStorage(
'key',
{},
undefined,
{
serializer: {
read: (v: any) => v ? JSON.parse(v) : null,
write: (v: any) => JSON.stringify(v),
},
},
)
请注意,当你提供 null 作为默认值时,useStorage 无法从中推断出数据类型。在这种情况下,你可以提供一个自定义序列化器,或者显式重用内置的序列化器。
import { StorageSerializers, useStorage } from '@vueuse/core'
const objectLike = useStorage('key', null, undefined, { serializer: StorageSerializers.object })
objectLike.value = { foo: 'bar' }
类型声明
export interface Serializer<T> {
read: (raw: string) => T
write: (value: T) => string
}
export interface SerializerAsync<T> {
read: (raw: string) => Awaitable<T>
write: (value: T) => Awaitable<string>
}
export declare const StorageSerializers: Record<
"boolean" | "object" | "number" | "any" | "string" | "map" | "set" | "date",
Serializer<any>
>
export declare const customStorageEventName = "vueuse-storage"
export interface StorageEventLike {
storageArea: StorageLike | null
key: StorageEvent["key"]
oldValue: StorageEvent["oldValue"]
newValue: StorageEvent["newValue"]
}
export interface UseStorageOptions<T>
extends ConfigurableEventFilter,
ConfigurableWindow,
ConfigurableFlush {
/**
* Watch for deep changes
*
* @default true
*/
deep?: boolean
/**
* Listen to storage changes, useful for multiple tabs application
*
* @default true
*/
listenToStorageChanges?: boolean
/**
* Write the default value to the storage when it does not exist
*
* @default true
*/
writeDefaults?: boolean
/**
* Merge the default value with the value read from the storage.
*
* When setting it to true, it will perform a **shallow merge** for objects.
* You can pass a function to perform custom merge (e.g. deep merge), for example:
*
* @default false
*/
mergeDefaults?: boolean | ((storageValue: T, defaults: T) => T)
/**
* Custom data serialization
*/
serializer?: Serializer<T>
/**
* On error callback
*
* Default log error to `console.error`
*/
onError?: (error: unknown) => void
/**
* Use shallow ref as reference
*
* @default false
*/
shallow?: boolean
/**
* Wait for the component to be mounted before reading the storage.
*
* @default false
*/
initOnMounted?: boolean
}
export declare function useStorage(
key: MaybeRefOrGetter<string>,
defaults: MaybeRefOrGetter<string>,
storage?: StorageLike,
options?: UseStorageOptions<string>,
): RemovableRef<string>
export declare function useStorage(
key: MaybeRefOrGetter<string>,
defaults: MaybeRefOrGetter<boolean>,
storage?: StorageLike,
options?: UseStorageOptions<boolean>,
): RemovableRef<boolean>
export declare function useStorage(
key: MaybeRefOrGetter<string>,
defaults: MaybeRefOrGetter<number>,
storage?: StorageLike,
options?: UseStorageOptions<number>,
): RemovableRef<number>
export declare function useStorage<T>(
key: MaybeRefOrGetter<string>,
defaults: MaybeRefOrGetter<T>,
storage?: StorageLike,
options?: UseStorageOptions<T>,
): RemovableRef<T>
export declare function useStorage<T = unknown>(
key: MaybeRefOrGetter<string>,
defaults: MaybeRefOrGetter<null>,
storage?: StorageLike,
options?: UseStorageOptions<T>,
): RemovableRef<T>