用es6 class封装indexeddb的核心是将打开数据库、建表、增删改查等重复逻辑抽象为可复用类,使调用如db.add('users', {id:1,name:'张三'})般简洁;需显式处理open、upgrade、ready三阶段,所有操作基于promise化事务,并支持索引查询与前缀匹配模糊搜索。

用 ES6 Class 封装 IndexedDB,核心是把数据库打开、建表、增删改查这些重复逻辑收进一个可复用的类里,避免每次手动写一堆 request 事件监听。关键不在“用不用 class”,而在于让调用像操作普通对象一样简单——比如 db.add('users', { id: 1, name: '张三' }),而不是反复处理 onsuccess 和 onupgradeneeded。
封装前先理清三个生命周期阶段
IndexedDB 操作天然分三步:打开数据库 → 确保表存在(升级时建表/建索引)→ 执行具体操作。封装类必须显式处理这三者,不能跳过或合并。
-
open():返回 Promise,内部监听
onsuccess和onupgradeneeded;失败直接 reject,成功缓存this.db -
upgrade():在
onupgradeneeded中调用,检查objectStoreNames.contains(storeName),只在不存在时创建 store 和索引 -
确保 ready:所有读写方法(如 add、get)都应先
await this.open()或检查this.db是否已就绪,否则会报 “database is not open”
定义基础操作方法(增删改查)
每个方法都基于事务(transaction),并统一用 Promise 包裹 request,避免回调地狱。注意:事务模式要匹配操作——读用 'readonly',写用 'readwrite'。
-
add(data, storeName):调用
transaction(storeName, 'readwrite').objectStore(...).add(data),主键由 keyPath 决定(如{ keyPath: 'id' }) -
get(id, storeName):用
.get(id),返回单条;若需全部数据,用.getAll() -
update(data, storeName):用
.put(data),自动覆盖同主键记录;区别于.add()的重复键报错 -
delete(id, storeName):用
.delete(id);支持按索引查询后批量删,需先index.openCursor()遍历
支持索引查询与模糊搜索
单纯靠主键查不够用,封装时要把索引能力暴露出来。例如建了 createIndex('by_name', 'name', { unique: false }),就能按 name 查:
- 用
store.index('by_name').get('张%')不行——IndexedDB 原生不支持 SQL 通配符 - 正确做法是:
store.index('by_name').openCursor(IDBKeyRange.bound('张', '张\uFFFF')),利用 Unicode 范围模拟前缀匹配 - 更灵活的模糊搜索可封装为方法:
searchByIndex(storeName, indexName, keyword, rangeType = 'prefix'),内部根据rangeType构造IDBKeyRange
注意单例与资源管理
同一个数据库名+版本不应同时打开多个连接,否则可能触发 blocked 事件。建议:
- 类实例化时传入唯一
dbName,内部用静态 Map 缓存已打开的 db 实例(DBCache.set(dbName, instance)) - 提供
close()方法主动调用this.db?.close(),尤其在 SPA 页面卸载时清理 - 暴露
deleteDB(dbName)静态方法,方便开发调试或用户清除数据











