WXT 存储
更新日志
一个简化扩展存储接口的封装。
安装
使用 WXT
该模块内置在 WXT 中,因此无需额外安装。
import { storage } from 'wxt/storage';
如果使用自动生成的导入,storage
会自动导入,因此无需甚至需要导入!
不使用 WXT
通过 npm 包装:
npm i @wxt-dev/storage
pnpm add @wxt-dev/storage
yarn add @wxt-dev/storage
bun add @wxt-dev/storage
import { storage } from '@wxt-dev/storage';
存储权限
要使用 wxt/storage
API,必须在配置中添加 "storage"
权限:
// wxt.config.ts
export default defineConfig({
manifest: {
permissions: ['storage'],
},
});
基本用法
所有存储键都必须以存储区域前缀。
// ❌ 这会抛出错误
await storage.getItem('installDate');
// ✅ 这是好的
await storage.getItem('local:installDate');
你可以使用 local:
, session:
, sync:
, 或 `managed:``。如果你使用 TypeScript,可以在大多数方法上添加类型参数来指定键值的预期类型:
await storage.getItem<number>('local:installDate');
await storage.watch<number>(
'local:installDate',
(newInstallDate, oldInstallDate) => {
// ...
},
);
await storage.getMeta<{ v: number }>('local:installDate');
要查看可用的所有方法,请参阅 API 参考.
监听变化
要监听存储变化,使用 storage.watch
函数。它让你可以设置一个监听器来为单个键:
const unwatch = storage.watch<number>('local:counter', (newCount, oldCount) => {
console.log('计数已改变:', { newCount, oldCount });
});
要移除监听器,调用返回的 unwatch
函数:
const unwatch = storage.watch(...);
// 一些时间后...
unwatch();
度量
wxt/storage
还支持为键设置度量,存储在 key + "$"
. 度量是一个由键相关属性集合组成的对象。它可以是版本号、最后修改日期等。
除了版本化,你负责管理一个字段的度量:
await Promise.all([
storage.setItem('local:preference', true),
storage.setMeta('local:preference', { lastModified: Date.now() }),
]);
当你从多个调用中设置不同属性时,这些属性会合并而不是被覆盖:
await storage.setMeta('local:preference', { lastModified: Date.now() });
await storage.setMeta('local:preference', { v: 2 });
await storage.getMeta('local:preference'); // { v: 2, lastModified: 1703690746007 }
你可以移除所有与键相关的度量,或仅特定属性:
// 移除所有属性
await storage.removeMeta('local:preference');
// 移除仅 `"lastModified"` 属性
await storage.removeMeta('local:preference', 'lastModified');
// 移除多个属性
await storage.removeMeta('local:preference', ['lastModified', 'v']);
定义存储项
写键和类型参数对所有存储键重复太多。作为替代,你可以使用 storage.defineItem
来创建一个“存储项”。
存储项包含与 storage
变量相同的 API,但你可以配置其类型、默认值和其他在一个地方:
// utils/storage.ts
const showChangelogOnUpdate = storage.defineItem<boolean>(
'local:showChangelogOnUpdate',
{
fallback: true,
},
);
现在,而不是使用存储变量,你可以使用你创建的存储项上的辅助函数:
await showChangelogOnUpdate.getValue();
await showChangelogOnUpdate.setValue(false);
await showChangelogOnUpdate.removeValue();
const unwatch = showChangelogOnUpdate.watch((newValue) => {
// ...
});
对于可用的所有属性和方法,请参阅 API 参考.
版本化
如果你预计存储项会变化或增长,你可以为存储项添加版本控制。当你定义第一个版本的存储项时,从 1 开始。
考虑一个存储项,它存储被 WXT 忽略的网站列表:
export const ignoredWebsites = storage.defineItem<string[]>(
'local:ignoredWebsites',
{
fallback: [],
},
);
import { nanoid } from 'nanoid';
// 恢复并添加一个类型以反向兼容 v1
type IgnoredWebsiteV1 = string;
interface IgnoredWebsiteV2 {
id: string;
website: string;
}
export const ignoredWebsites = storage.defineItem<string[]>(
export const ignoredWebsites = storage.defineItem<IgnoredWebsiteV2[]>(
'local:ignoredWebsites',
{
fallback: [],
version: 2,
migrations: {
// 迁移到 v1 到 v2
2: (websites: IgnoredWebsiteV1[]): IgnoredWebsiteV2[] => {
return websites.map((website) => ({ id: nanoid(), website }));
},
},
},
);
迁移
一旦 storage.defineItem
被调用,WXT 会检查是否需要运行迁移,并如果需要则运行它们。读取或写入存储项值(例如 getValue
, setValue
, removeValue
, getMeta
, 等等)将自动等待迁移过程完成,然后再实际读取或写入值。
默认值
使用 storage.defineItem
有多种方式定义默认值:
fallback
- 如果值缺失,则返回此值而不是null
。这对提供默认值的设置非常有用:
typescriptconst theme = storage.defineItem('local:theme', { fallback: 'dark', }); const allowEditing = storage.defineItem('local:allow-editing', { fallback: true, });
init
- 初始化并保存到存储如果尚未保存。这对需要初始化或只在一次时设置的值非常有用:
typescriptconst userId = storage.defineItem('local:user-id', { init: () => globalThis.crypto.randomUUID(), }); const installDate = storage.defineItem('local:install-date', { init: () => new Date().getTime(), });
值在存储中立即初始化。
批处理操作
获取或设置多个存储值时,你可以执行批处理操作以提高性能。storage
API 提供了进行批量操作的方法:
getItems
- 获取多个值。getMetas
- 获取多个项的度量。setItems
- 设置多个值。setMetas
- 设置多个项的度量。removeItems
- 移除多个值(并可选地移除度量)。
所有这些 API 支持字符串键和定义的存储项:
const userId = storage.defineItem('local:userId');
await storage.setItems([
{ key: 'local:installDate', value: Date.now() },
{ item: userId, value: generateUserId() },
]);
有关更多类型和示例,请参阅 API 参考.