ux-web-storage
v1.0.7
Published
增强版 Web Storage 工具库,支持 `localStorage`、`sessionStorage` 代理读写,以及 IndexedDB 封装。
Maintainers
Readme
ux-web-storage
增强版 Web Storage 工具库,支持 localStorage、sessionStorage 代理读写,以及 IndexedDB 封装。
安装
npm i ux-web-storage快速开始
import { local, session, db, setPrefix } from 'ux-web-storage'
// 可选:设置 key 前缀,避免和其他库冲突
setPrefix('my-app')
local.user = { name: 'Tom' }
local.user.name = 'Jerry' // 嵌套修改自动同步
session.token = 'abc'
await db.set('config', { theme: 'dark' })
const config = await db.get('config')local / session
local 和 session API 完全一致,区别仅在于底层存储(localStorage vs sessionStorage)。
基础读写
支持直接赋值、删除,类型保持不变:
local.test = 'hello'
local.test = 0
local.test = false
local.test = null
local.test = undefined
delete local.test
local.test = { hello: 'world' }
local.test.hello = 'world' // 嵌套对象可直接改
local.test = ['a']
local.test.push('b')
local.test = new Date()
local.test = /abc/g
local.test = () => 'hi'也支持原生风格 API:
local.setItem('key', value)
local.getItem('key')
local.removeItem('key')
local.clear()
local.key(0)
local.length订阅变更
local.on('user', (newVal, oldVal) => {
console.log(newVal, oldVal)
})
// 监听嵌套属性
local.on('user.name', (newVal, oldVal) => {})
local.once('token', fn) // 只触发一次
local.off('token', fn) // 取消订阅
local.off('token') // 取消该 key 所有订阅
local.off() // 取消所有订阅过期时间
// 10 秒后过期(毫秒)
local.setItem('token', 'xxx', { expires: 10000 })
// 或
local.setExpires('token', 10000)
local.getExpires('token') // => Date
local.removeExpires('token')过期后读取返回 undefined,并在读取时自动删除。页面启动时也会扫描清理过期项。
一次性读取(disposable)
local.setItem('code', '123456', { disposable: true })
local.code // '123456'
local.code // undefined(第二次读自动删除)跨标签页同步
local 支持浏览器 storage 事件,其他标签页修改后会触发 local.on 回调。session 仅在当前标签页有效。
IndexedDB(db)
所有读写方法都是 异步的,需要 await 或 .then()。
两种用法
| 场景 | 用法 |
|------|------|
| 整个项目只用一个 store | configureDefaultStore + db.get/set |
| 多个 store 或跨模块 | registerDb + useDb(或 getDb) |
单 store:configureDefaultStore + db.*
默认使用 indexdb-store / indexdb,也可在 第一次读写前 改成自己的:
import { db } from 'ux-web-storage'
// 可选,入口执行一次
db.configureDefaultStore('my-app', 'main')
await db.set('uid', 1)
await db.set('token', 'abc', 60000) // 第三参数:过期毫秒数
const uid = await db.get('uid')
const list = await db.getMany(['uid', 'token'])
await db.setMany([
['a', 1],
['b', 2],
])
await db.update('uid', old => (old ?? 0) + 1)
await db.del('token')
await db.delMany(['a', 'b'])
await db.clear()
const allKeys = await db.keys()
const allValues = await db.values()
const allEntries = await db.entries()
db.on('uid', val => console.log(val))
db.off('uid', callback)过期时间
// set:第三参数为过期毫秒数
await db.set('token', 'abc', 60000)
// setMany:第二参数为过期毫秒数,作用于本批所有 key
await db.setMany([
['a', 1],
['b', 2],
], 60000)
// update:第三参数可选
await db.update('uid', old => (old ?? 0) + 1) // 只改值,保留原过期时间
await db.update('token', old => old, 60000) // 改值并重置过期时间
await db.update('token', old => old, 0) // 改值并清除过期(永不过期)
// 过期后 get 返回 undefined,并自动删除
const token = await db.get('token')| 方法 | 过期参数 | 行为 |
|------|----------|------|
| set(key, val, expire?) | 第 3 参数 | 设置值 + 过期时间 |
| setMany(entries, expire?) | 第 2 参数 | 批量写入,同一过期时间作用于所有 key |
| update(key, fn, expire?) | 第 3 参数 | 不传:只更新值,保留原过期;传毫秒数:重置过期;传 0:清除过期 |
订阅变更(含过期)
const users = db.useDb('users')
users.on('token', (val) => {
console.log(val)
})
await users.set('token', 'abc')
// 写入事件 => 'abc'
await users.setMany([['a', 1], ['b', 2]], 60000)
// 写入事件 => 1、2(各 key 的 on 分别触发)
await users.update('a', old => (old ?? 0) + 1)
// 写入事件 => 新值(保留原过期时间)
await users.set('token', 'abc', 1000)
// 写入事件 => 'abc'
// 过期后首次 get / getMany / values / entries 触发清理:
// 过期事件 => null说明:
- 写入类操作(
set/setMany/update)成功后,on触发 新值 - 删除 / 过期清理时,
on触发null setMany会对每个 key 分别触发一次onupdate不传过期参数时 不会 改变过期时间,只更新业务值- 过期仍是 惰性清理:到点后不会自动触发,需读取时才清理并通知
null
多 store:registerDb + useDb
方式 1:getDb() — 推荐
相同 (dbName, storeName) 全局共享同一实例,不同模块直接调用即可,无需重复初始化:
// module-a.ts
await db.getDb('my-app', 'users').set('uid', 1)
// module-b.ts
const uid = await db.getDb('my-app', 'users').get('uid')createDb() 是 getDb() 的别名。
方式 2:registerDb + useDb — 跨模块更简洁
// main.ts(入口执行一次)
db.registerDb('users', 'my-app', 'users')
db.registerDb('cache', 'my-app', 'cache')
// 任意模块
const users = db.useDb('users') // 同步,不需要 await
await users.set('uid', 1)
const uid = await users.get('uid')
users.on('uid', val => console.log(val))
users.off('uid', callback)async / await 说明
| 方法 | 是否异步 | 需要 await |
|------|----------|-----------|
| useDb() / getDb() | 否 | 否 |
| on() / off() | 否 | 否 |
| get/set/del/clear/... | 是 | 是 |
// ✅
const users = db.useDb('users')
await users.set('uid', 1)
const uid = await users.get('uid')
// ❌ uid 是 Promise,不是实际值
const uid = users.get('uid')
// ❌ set 没 await,get 可能读到旧值
users.set('uid', 1)
const uid = await users.get('uid')同一数据库多个 Object Store
同一个 database 下可以随意注册多个 store,库会自动检测并创建缺失的 store:
// 任意顺序、任意模块,直接写就行
db.registerDb('users', 'my-app', 'users')
db.registerDb('cache', 'my-app', 'cache')
db.registerDb('logs', 'my-app', 'logs')
await db.useDb('users').set('uid', 1)
await db.useDb('cache').set('theme', 'dark')API 一览
导出
| 导出 | 说明 |
|------|------|
| local | localStorage 代理 |
| session | sessionStorage 代理 |
| db | IndexedDB 模块 |
| setPrefix(prefix) | 设置 local/session key 前缀 |
db 方法
| 方法 | 说明 |
|------|------|
| configureDefaultStore(db, store) | 配置默认 store |
| getDb(db, store) | 获取共享 db 实例 |
| createDb(db, store) | 同 getDb |
| registerDb(name, db, store) | 注册命名实例 |
| useDb(name) | 获取命名实例 |
| get/set/setMany/getMany/update | 默认 store 读写 |
| del/delMany/clear | 删除 |
| keys/values/entries | 批量查询 |
| on/off | 订阅 / 取消订阅 |
注意事项
- Function / RegExp 序列化使用
eval还原,仅建议在可信环境使用。 - IndexedDB 容量 远大于 localStorage,适合存较大数据。
- 默认 db 与 getDb 默认 store 互通:
db.set()和db.getDb('indexdb-store', 'indexdb').get()读写同一数据,db.on()与实例.on()共享订阅。 - 不同 store 的
on相互隔离,相同 key 名不会串扰。
