核心实现思路
IndexedDB 是异步操作的 API,核心步骤分为:
- 打开 / 创建数据库(指定名称和版本)
- 监听数据库升级事件(用于创建 / 修改对象仓库)
- 处理打开成功 / 失败的回调
- 封装常用的增删查操作
创建一个公共文件
// IndexedDB 操作的工具函数
class IndexedDBHelper {
constructor(dbName, storeName, version = 1) {
this.dbName = dbName; // 数据库名称
this.storeName = storeName; // 对象仓库名称(类似表名)
this.version = version; // 数据库版本
this.db = null; // 保存打开的数据库实例
}
// 打开数据库的核心方法
openDB() {
return new Promise((resolve, reject) => {
// 1. 调用 indexedDB.open 打开/创建数据库
const request = indexedDB.open(this.dbName, this.version);
// 2. 数据库升级事件(版本号提升时触发,用于初始化/修改结构)
request.onupgradeneeded = (event) => {
this.db = event.target.result;
console.log('数据库版本升级,当前版本:', event.oldVersion);
// 判断对象仓库是否存在,不存在则创建(指定主键)
if (!this.db.objectStoreNames.contains(this.storeName)) {
// 创建对象仓库,指定主键为 id,且自增
const objectStore = this.db.createObjectStore(this.storeName, {
keyPath: 'id',
autoIncrement: true
});
// 可选:创建索引,方便查询(比如按 name 索引)
objectStore.createIndex('nameIndex', 'name', { unique: false });
}
};
// 3. 数据库打开成功
request.onsuccess = (event) => {
this.db = event.target.result;
console.log('数据库打开成功');
resolve(this.db); // 成功回调返回数据库实例
};
// 4. 数据库打开失败
request.onerror = (event) => {
console.error('数据库打开失败:', event.target.error);
reject(event.target.error); // 失败回调返回错误
};
// 5. 数据库被意外关闭
request.onblocked = () => {
console.error('数据库被占用,无法打开/升级');
reject(new Error('数据库被占用,请关闭其他标签页后重试'));
};
});
}
// 封装:添加数据
addData(data) {
if (!this.db) throw new Error('数据库未打开');
// 创建事务,指定操作的仓库和读写模式
const transaction = this.db.transaction(this.storeName, 'readwrite');
const store = transaction.objectStore(this.storeName);
const request = store.add(data);
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve('数据添加成功');
request.onerror = (e) => reject(e.target.error);
});
}
/**读取数据库数据*/
getAllData(id) {
if (!this.db) throw new Error('数据库未打开');
const transaction = this.db.transaction(this.storeName, 'readonly');
const store = transaction.objectStore(this.storeName);
let request = null
if (id) {
request = store.get(id);
} else {
request = store.getAll();
}
return new Promise((resolve, reject) => {
request.onsuccess = (e) => resolve(e.target.result);
request.onerror = (e) => reject(e.target.error);
});
}
/**根据主键删除数据*/
deleteData(id) {
if (!this.db) throw new Error('数据库未打开');
const transaction = this.db.transaction(this.storeName, 'readwrite');
const store = transaction.objectStore(this.storeName);
const request = store.delete(id);
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve('数据删除成功');
request.onerror = (e) => reject(e.target.error);
});
}
// 封装:关闭数据库
closeDB() {
if (this.db) {
this.db.close();
console.log('数据库已关闭');
}
}
}
// ===================== 调用示例 =====================
// 1. 创建数据库助手实例(数据库名:myDB,对象仓库名:user,版本:1)
export const dbHelper = new IndexedDBHelper('myDB', 'user', 1);
// 页面关闭时关闭数据库
window.addEventListener('beforeunload', () => {
dbHelper.closeDB();
});
导入需要使用到IndexedDB
import { dbHelper } from './dbHelper.js'
将文件切割好装入IndexedDB
/**切割好的文件Blob*/
let fileList = null
let file = ref(null)
async function handleFileChange(event) {
file.value = event.target.files[0]
fileList = _fileCutting(file.value, 10 * 1024 * 1024)
try {
// 打开数据库
await dbHelper.openDB()
// 增加数据
await dbHelper.addData({ name: '文件', fileList })
} catch (error) {
console.log(error)
}
}
/**切割file*/
function _fileCutting(file, size) {
let fileList = []
for (let i = 0; i < file.size; i += size) {
fileList.push(file.slice(i, i + size))
}
return fileList
}