浏览器端使用indexedDB存储
你想知道如何在 IndexedDB 中根据 name(姓名)字段来查询数据,这是 IndexedDB 最常见的查询场景之一。要实现按姓名精准查找,核心是先为 name 字段创建索引,再通过索引进行查询。
一、完整实现代码(含建库、建索引、按姓名查询)
下面是一个开箱即用的完整示例,包含数据库初始化、创建索引、添加数据、按姓名查询的全部逻辑:
// 封装 IndexedDB 操作的工具函数
class IndexedDBHelper {
constructor(dbName, storeName, version = 1) {
this.dbName = dbName; // 数据库名
this.storeName = storeName; // 对象仓库名
this.version = version; // 数据库版本
this.db = null; // 数据库实例
}
// 1. 初始化数据库(创建仓库 + 为name字段建索引)
async initDB() {
return new Promise((resolve, reject) => {
// 打开数据库
const request = indexedDB.open(this.dbName, this.version);
// 数据库首次创建/版本升级时触发(用于初始化结构)
request.onupgradeneeded = (e) => {
this.db = e.target.result;
// 如果仓库不存在,创建仓库(主键设为id,自增)
if (!this.db.objectStoreNames.contains(this.storeName)) {
const store = this.db.createObjectStore(this.storeName, {
keyPath: 'id',
autoIncrement: true // id 自动递增
});
// 为 name 字段创建索引(name索引名,字段名,是否唯一:false表示允许多人同名)
store.createIndex('nameIndex', 'name', { unique: false });
console.log('仓库和name索引创建成功');
}
};
// 打开数据库成功
request.onsuccess = (e) => {
this.db = e.target.result;
resolve(this.db);
};
// 打开数据库失败
request.onerror = (e) => {
reject(new Error('打开数据库失败:' + e.target.error));
};
});
}
// 2. 新增数据(示例:添加用户)
async addUser(user) {
if (!this.db) await this.initDB();
return new Promise((resolve, reject) => {
// 开启读写事务
const transaction = this.db.transaction(this.storeName, 'readwrite');
const store = transaction.objectStore(this.storeName);
const request = store.add(user); // 添加数据
request.onsuccess = () => resolve('添加成功');
request.onerror = (e) => reject(new Error('添加失败:' + e.target.error));
});
}
// 3. 核心:按姓名(name)查询数据
async queryByName(name) {
if (!this.db) await this.initDB();
return new Promise((resolve, reject) => {
// 开启只读事务
const transaction = this.db.transaction(this.storeName, 'readonly');
const store = transaction.objectStore(this.storeName);
// 获取之前创建的name索引
const nameIndex = store.index('nameIndex');
// 按索引查询(精准匹配name)
const request = nameIndex.getAll(name); // getAll:返回所有匹配结果;get:返回第一个匹配结果
request.onsuccess = (e) => {
resolve(e.target.result); // 结果是数组(即使只有1条)
};
request.onerror = (e) => {
reject(new Error('查询失败:' + e.target.error));
};
});
}
}
// ------------------- 测试使用 -------------------
(async () => {
// 初始化:数据库名「userDB」,对象仓库名「userStore」
const dbHelper = new IndexedDBHelper('userDB', 'userStore');
await dbHelper.initDB();
// 先添加几条测试数据
await dbHelper.addUser({ name: '张三', age: 25, phone: '13800138000' });
await dbHelper.addUser({ name: '李四', age: 30, phone: '13900139000' });
await dbHelper.addUser({ name: '张三', age: 28, phone: '13700137000' }); // 同名数据
// 按姓名查询:查「张三」
const result = await dbHelper.queryByName('张三');
console.log('查询结果:', result);
// 输出:[{id:1, name:'张三', age:25, phone:'13800138000'}, {id:3, name:'张三', age:28, phone:'13700137000'}]
})();
二、关键逻辑解释
创建索引是前提:
在 onupgradeneeded 阶段(数据库初始化 / 升级),通过 store.createIndex('nameIndex', 'name', { unique: false }) 创建索引:
第一个参数 nameIndex:索引名称(自定义,后续查询要用到);
第二个参数 name:要索引的字段名(即你要查询的姓名字段);
第三个参数 unique: false:表示允许多条数据的 name 字段值相同(如果设为 true,则姓名不能重复)。
按索引查询的核心 API:
index.getAll(name):返回所有姓名匹配的结果(数组),适合处理 “同名” 场景;
index.get(name):返回第一个匹配的结果(单个对象),适合确认 “是否存在该姓名” 或 “姓名唯一” 的场景;
两者的区别:如果有多个 “张三”,get 只返回第一条,getAll 返回全部。
事务类型:
查询操作用 readonly(只读)事务,性能更高;
增删改操作必须用 readwrite(读写)事务。
三、扩展:模糊查询姓名(可选)
如果你需要 “模糊查询”(比如输入 “张”,查出所有姓张的人),可以用索引的范围查询:
// 新增模糊查询方法(加到 IndexedDBHelper 类中)
async queryByNameFuzzy(keyword) {
if (!this.db) await this.initDB();
return new Promise((resolve, reject) => {
const transaction = this.db.transaction(this.storeName, 'readonly');
const store = transaction.objectStore(this.storeName);
const nameIndex = store.index('nameIndex');
// 范围:以keyword开头(如keyword='张',匹配所有以张开头的姓名)
const range = IDBKeyRange.bound(keyword, keyword + '\uffff');
const request = nameIndex.getAll(range);
request.onsuccess = (e) => resolve(e.target.result);
request.onerror = (e) => reject(new Error('模糊查询失败:' + e.target.error));
});
}
// 调用:查询所有姓张的人
// const fuzzyResult = await dbHelper.queryByNameFuzzy('张');
// console.log('模糊查询结果:', fuzzyResult);
总结
按姓名查询 IndexedDB 的核心是先为 name 字段创建索引,再通过索引查询;
精准查询用 index.get(name)(单条)或 index.getAll(name)(多条),模糊查询用 IDBKeyRange 范围匹配;
操作 IndexedDB 必须通过事务,查询用只读事务,增删改用读写事务。
简单的代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>IndexedDB 增删改查示例</title> </head> <body> <button id="addBtn">添加数据</button> <button id="addBtns">添加数据</button> <button id="deleteBtn">删除数据</button> <button id="updateBtn">更新数据</button> <button id="queryBtn">查询数据</button> <button id="queryBtns">删除数据库</button> <script> // 打开或创建数据库 const request = indexedDB.open('myDatabase', 1); // 数据库打开失败 request.onerror = function (event) { console.error('数据库打开失败:', event.target.errorCode); }; // 数据库打开成功 request.onsuccess = function (event) { const db = event.target.result; console.log('数据库打开成功'); // 添加数据 document.getElementById('addBtn').addEventListener('click', function () { const transaction = db.transaction(['myObjectStore'], 'readwrite'); const objectStore = transaction.objectStore('myObjectStore'); const data = { id: 1, name: '李强', age: 30 }; const addRequest = objectStore.add(data); addRequest.onsuccess = function () { console.log('数据添加成功'); }; addRequest.onerror = function (event) { console.error('数据添加失败:', event.target.errorCode); }; }); document.getElementById('addBtns').addEventListener('click', function () { const transaction = db.transaction(['myObjectStore'], 'readwrite'); const objectStore = transaction.objectStore('myObjectStore'); const data = { id: 64, name: '李是强', age: 30 }; const addRequest = objectStore.add(data); addRequest.onsuccess = function () { console.log('数据添加成功'); }; addRequest.onerror = function (event) { console.error('数据添加失败:', event.target.errorCode); }; }); // 删除数据 document.getElementById('deleteBtn').addEventListener('click', function () { const transaction = db.transaction(['myObjectStore'], 'readwrite'); const objectStore = transaction.objectStore('myObjectStore'); const deleteRequest = objectStore.delete(1); deleteRequest.onsuccess = function () { console.log('数据删除成功'); }; deleteRequest.onerror = function (event) { console.error('数据删除失败:', event.target.errorCode); }; }); // 更新数据 document.getElementById('updateBtn').addEventListener('click', function () { const transaction = db.transaction(['myObjectStore'], 'readwrite'); const objectStore = transaction.objectStore('myObjectStore'); const data = { id: 1, name: 'Jane', age: 30 }; const putRequest = objectStore.put(data); putRequest.onsuccess = function () { console.log('数据更新成功'); }; putRequest.onerror = function (event) { console.error('数据更新失败:', event.target.errorCode); }; }); // 查询数据 document.getElementById('queryBtn').addEventListener('click', function () { const transaction = db.transaction(['myObjectStore'], 'readonly'); const objectStore = transaction.objectStore('myObjectStore'); // const getRequest = objectStore.get(1); //按照主键查找 // const getRequest = objectStore.index('name').get('李强'); //按照主键查找 // const getRequest = objectStore.index('name').getAll('李强'); //按照索引查找 const getRequest = objectStore.getAll(); //查找全部 getRequest.onsuccess = function (event) { const result = event.target.result; if (result) { console.log('查询结果:', result); } else { console.log('未找到数据'); } }; getRequest.onerror = function (event) { console.error('数据查询失败:', event.target.errorCode); }; }); }; // 数据库版本更新时创建对象仓库和索引 request.onupgradeneeded = function (event) { const db = event.target.result; if (!db.objectStoreNames.contains('myObjectStore')) { const objectStore = db.createObjectStore('myObjectStore', { keyPath: 'id' }); objectStore.createIndex('name', 'name', { unique: false }); objectStore.createIndex('age', 'age', { unique: false }); } }; </script> </body> </html>
图片上传保存并获取展示
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IndexedDB 图片存储(原生JS)</title>
<style>
.preview { border: 1px solid #ddd; min-height: 300px; margin: 20px 0; }
button { padding: 8px 12px; margin-right: 10px; }
</style>
</head>
<body>
<input type="file" id="fileInput" accept="image/*">
<button id="storeBtn">存储图片</button>
<button id="loadBtn">加载最新图片</button>
<div class="preview">
<img id="dbImage" style="max-width: 100%; display: none;">
</div>
<div id="status">就绪</div>
<script>
// 核心配置
const DB_NAME = "ImageDB";
const STORE_NAME = "images";
const DB_VERSION = 1;
let db = null;
// 状态更新
function updateStatus(message) {
document.getElementById('status').textContent = message;
}
// 1. 初始化数据库(Promise封装)
function initDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(DB_NAME, DB_VERSION);
// 数据库结构升级
request.onupgradeneeded = (event) => {
const db = event.target.result;
// 关键修复:确保对象存储存在
if (!db.objectStoreNames.contains(STORE_NAME)) {
db.createObjectStore(STORE_NAME, {
keyPath: 'id',
autoIncrement: true
});
updateStatus("对象存储创建成功");
}
};
request.onsuccess = (event) => {
db = event.target.result;
updateStatus("数据库已连接");
resolve(db);
};
request.onerror = (event) => {
updateStatus(`数据库错误: ${event.target.error}`);
reject(event.target.error);
};
});
}
// 2. 存储图片到数据库
async function storeImage() {
const file = document.getElementById('fileInput').files[0];
if (!file) {
updateStatus("请选择图片文件");
return;
}
try {
// 读取为ArrayBuffer(兼容性更好)
const arrayBuffer = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = () => reject(reader.error);
reader.readAsArrayBuffer(file);
});
const transaction = db.transaction([STORE_NAME], 'readwrite');
const store = transaction.objectStore(STORE_NAME);
// 构建元数据对象
const imageData = {
name: file.name,
type: file.type,
size: file.size,
timestamp: new Date(),
imageData: arrayBuffer
};
// 存储操作
const request = store.add(imageData);
request.onsuccess = () => {
updateStatus(`图片存储成功 ID: ${request.result}`);
};
request.onerror = (event) => {
updateStatus(`存储失败: ${event.target.error}`);
};
} catch (error) {
updateStatus(`错误: ${error.message}`);
}
}
// 3. 从数据库加载最新图片
async function loadLatestImage() {
const transaction = db.transaction([STORE_NAME], 'readonly');
const store = transaction.objectStore(STORE_NAME);
const request = store.openCursor(null, 'prev'); // 反向遍历取最新
request.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
displayImage(cursor.value);
} else {
updateStatus("数据库中没有图片");
}
};
request.onerror = (event) => {
updateStatus(`加载失败: ${event.target.error}`);
};
}
// 4. 显示图片
function displayImage(imageRecord) {
const blob = new Blob([imageRecord.imageData], { type: imageRecord.type });
const imageUrl = URL.createObjectURL(blob);
const imgElement = document.getElementById('dbImage');
imgElement.src = imageUrl;
imgElement.style.display = 'block';
imgElement.alt = `已加载: ${imageRecord.name}`;
// 释放内存
imgElement.onload = () => URL.revokeObjectURL(imageUrl);
updateStatus(`已加载: ${imageRecord.name} (${formatBytes(imageRecord.size)})`);
}
// 辅助函数:格式化文件大小
function formatBytes(bytes) {
const units = ['B', 'KB', 'MB', 'GB'];
let size = bytes;
let unitIndex = 0;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${size.toFixed(2)} ${units[unitIndex]}`;
}
// 5. 初始化应用
window.addEventListener('DOMContentLoaded', async () => {
updateStatus("正在初始化数据库...");
try {
await initDB();
// 绑定事件
document.getElementById('storeBtn').addEventListener('click', storeImage);
document.getElementById('loadBtn').addEventListener('click', loadLatestImage);
updateStatus("就绪:选择图片后点击存储");
} catch (error) {
updateStatus(`初始化失败: ${error.message}`);
}
});
</script>
</body>
</html>
uniapp中VUE3封装使用
在utils创建一个groupChatDb.js
/**
* IndexedDB 封装工具类(适配 UniApp H5 + Vue3)
* 仅支持 H5 环境,其他端提示不支持
*/
class UniIndexedDB {
constructor(dbName = 'myDatabase', storeName = 'myObjectStore', version = 1) {
this.dbName = dbName;
this.storeName = storeName;
this.version = version;
this.db = null;
this.isSupport = this.checkSupport();
}
// 检查环境是否支持 IndexedDB
checkSupport() {
// #ifdef H5
return !!window.indexedDB;
// #endif
// #ifndef H5
uni.showToast({
title: '当前环境不支持IndexedDB',
icon: 'none'
});
return false;
// #endif
}
// 打开/创建数据库
openDB() {
return new Promise((resolve, reject) => {
if (!this.isSupport) {
reject(new Error('当前环境不支持IndexedDB'));
return;
}
const request = window.indexedDB.open(this.dbName, this.version);
// 版本更新/首次创建时初始化仓库
request.onupgradeneeded = (event) => {
this.db = event.target.result;
if (!this.db.objectStoreNames.contains(this.storeName)) {
// ========== 1开启autoIncrement,指定主键fid自增 ==========
const objectStore = this.db.createObjectStore(this.storeName, {
keyPath: 'fid', // 主键字段仍为fid
autoIncrement: true // 核心:开启原生自增
});
objectStore.createIndex('id', 'id', {unique: false});
objectStore.createIndex('conversationsId', 'conversationsId', {unique: false});
// 新增:为fid创建索引(方便排序查询,虽然主键本身可直接排序,但显式索引更清晰)
objectStore.createIndex('fid', 'fid', {unique: true});
}
};
// 打开成功
request.onsuccess = (event) => {
this.db = event.target.result;
resolve('数据库打开成功');
};
// 打开失败
request.onerror = (event) => {
reject(new Error(`数据库打开失败: ${event.target.error}`));
};
});
}
// 关闭数据库
closeDB() {
if (this.db) {
this.db.close();
this.db = null;
}
}
// 删除整个数据库(核心功能)
deleteDB() {
return new Promise((resolve, reject) => {
if (!this.isSupport) {
reject(new Error('当前环境不支持IndexedDB'));
return;
}
// 先关闭已打开的连接
this.closeDB();
const request = window.indexedDB.deleteDatabase(this.dbName);
request.onsuccess = () => {
resolve('数据库删除成功');
};
request.onerror = (event) => {
reject(new Error(`数据库删除失败: ${event.target.error}`));
};
// 有未关闭的连接时触发
request.onblocked = () => {
reject(new Error('数据库删除被阻止:存在未关闭的连接'));
};
});
}
// 通用事务处理(封装重复逻辑)
_transaction(mode, callback) {
return new Promise((resolve, reject) => {
if (!this.db) {
reject(new Error('数据库未打开,请先调用openDB'))
return;
}
try {
const transaction = this.db.transaction(this.storeName, mode);
const objectStore = transaction.objectStore(this.storeName);
resolve(callback(objectStore));
} catch (error) {
reject(error);
}
});
}
// 根据主键fID查询数据
queryDataByFid(fid) {
return this._transaction('readonly', (objectStore) => {
return new Promise((resolve, reject) => {
const request = objectStore.get(fid);
request.onsuccess = (event) => resolve(event.target.result);
request.onerror = (event) => reject(new Error(`查询失败: ${event.target.error}`));
});
});
}
// 根据 id 查询 这个id是 聊天信息id
queryDataById(id) {
return this._transaction('readonly', (objectStore) => {
return new Promise((resolve, reject) => {
const request = objectStore.index('id').get(id); //按照主键查找
request.onsuccess = (event) => resolve(event.target.result);
request.onerror = (event) => reject(new Error(`查询失败: ${event.target.error}`));
});
});
}
//根据群组唯一id查询所有群组数据 - 分页
queryDataAllId(conversationsId, pageNum = 1, pageSize = 10) {
const self = this
return this._transaction('readonly', (objectStore) => {
return new Promise((resolve, reject) => {
try {
const index = objectStore.index('conversationsId');
const range = IDBKeyRange.only(conversationsId);
const countRequest = index.count(range);
countRequest.onsuccess = () => {
const total = countRequest.result;
const totalPage = Math.ceil(total / pageSize);
let resultList = [];
const start = (pageNum - 1) * pageSize;
const end = pageNum * pageSize;
// 提前判断页码越界
if (pageNum > totalPage) {
resolve({
list: [],
total: total,
pageNum: pageNum,
pageSize: pageSize,
totalPage: totalPage,
hasMore: false
});
return;
}
let currentIndex = 0;
const cursorRequest = index.openCursor(range, 'prev');
cursorRequest.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
if (currentIndex >= start && currentIndex < end) {
resultList.push(cursor.value);
}
currentIndex++;
if (currentIndex >= end) {
cursor.continue = () => {};
resolveResult();
return;
}
cursor.continue();
} else {
resolveResult();
}
};
cursorRequest.onerror = (event) => {
reject(new Error(`分页查询失败: ${event.target.error}`));
};
function resolveResult() {
resolve({
list: self.transformContentJson(resultList),
total: total,
pageNum: pageNum,
pageSize: pageSize,
totalPage: totalPage,
hasMore: pageNum < totalPage
});
}
};
countRequest.onerror = (event) => {
reject(new Error(`统计总条数失败: ${event.target.error}`));
};
} catch (error) {
reject(new Error(`分页查询异常: ${error.message}`));
}
});
});
}
//根据群组唯一id查询所有群组数据 不分页
noPageDataAllId(conversationsId) {
return this._transaction('readonly', (objectStore) => {
return new Promise((resolve, reject) => {
const request = objectStore.index('conversationsId').getAll(conversationsId); //按照群组id查找
request.onsuccess = (event) => resolve(this.transformContentJson(event.target.result));
request.onerror = (event) => reject(new Error(`查询失败: ${event.target.error}`));
});
});
}
//获取所有的数据
queryDataAll(conversationsId) {
return this._transaction('readonly', (objectStore) => {
return new Promise((resolve, reject) => {
const request = objectStore.getAll();
request.onsuccess = (event) => resolve(event.target.result);
request.onerror = (event) => reject(new Error(`查询失败: ${event.target.error}`));
});
});
}
// 添加数据(无需传fid,自动生成)
addData(data) {
return this._transaction('readwrite', (objectStore) => {
return new Promise((resolve, reject) => {
const request = objectStore.add(data);
// 成功时返回自动生成的fid(event.target.result就是自增的fid)
request.onsuccess = (event) => resolve({
msg: '数据添加成功',
fid: event.target.result // 返回自动生成的主键ID
});
request.onerror = (event) => reject(new Error(`添加失败: ${event.target.error}`));
});
});
}
// 删除单条数据(根据fid删除)不传直接清空
deleteData(id = null) {
return this._transaction('readwrite', (objectStore) => {
return new Promise((resolve, reject) => {
let request
if(id){
request = objectStore.delete(id);
}else{
request = objectStore.clear();
}
request.onsuccess = () => resolve('数据删除成功');
request.onerror = (event) => reject(new Error(`删除失败: ${event.target.error}`));
});
});
}
// 新增:批量删除指定conversationsId的所有数据
deleteDataByConversationsId(conversationsId) {
return this._transaction('readwrite', (objectStore) => {
return new Promise((resolve, reject) => {
try {
// 1. 获取conversationsId索引
const index = objectStore.index('conversationsId');
// 2. 创建匹配指定conversationsId的范围
const range = IDBKeyRange.only(conversationsId);
// 3. 打开游标遍历所有匹配的数据
const request = index.openCursor(range);
let deleteCount = 0; // 统计删除的条数
request.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
// 4. 删除当前游标指向的数据(通过主键fid删除)
cursor.delete();
deleteCount++;
// 5. 继续遍历下一条
cursor.continue();
} else {
// 6. 游标遍历完成,返回删除结果
if (deleteCount === 0) {
resolve(`未找到conversationsId为${conversationsId}的数据,无需删除`);
} else {
resolve(`成功删除${deleteCount}条conversationsId为${conversationsId}的数据`);
}
}
};
request.onerror = (event) => {
reject(new Error(`批量删除失败: ${event.target.error}`));
};
} catch (error) {
reject(new Error(`批量删除异常: ${error.message}`));
}
});
});
}
// 更新数据(需传入包含fid的完整数据)
updateData(data) {
return this._transaction('readwrite', (objectStore) => {
return new Promise((resolve, reject) => {
const request = objectStore.put(this.purifyData(data));
request.onsuccess = () => resolve('数据更新成功');
request.onerror = (event) => reject(new Error(`更新失败: ${event.target.error}`));
});
});
}
transformContentJson(arr) {
// 边界校验:非数组返回空数组或原数据
if (!Array.isArray(arr)) {
console.warn('传入的参数不是数组');
return arr || [];
}
// 需要转换为布尔值的字段列表
const booleanFields = ['joinGroups', 'leaveGroups', 'atmosphere', 'mute', 'revoke', 'revokeEdit', 'chat', 'violation', 'longPress'];
return arr.map(item => {
// 浅拷贝原对象,避免修改原始数据
const newItem = { ...item };
// 第一步:处理contentJson字段(字符串 → 对象/null)
const contentJsonStr = newItem.contentJson;
try {
if (contentJsonStr === "NULL" || contentJsonStr === null) {
newItem.contentJson = null;
} else if (typeof contentJsonStr === 'string' && contentJsonStr.trim() !== '') {
newItem.contentJson = JSON.parse(contentJsonStr);
}else {
newItem.contentJson = contentJsonStr;
}
} catch (error) {
console.error(`解析contentJson失败:${contentJsonStr},错误:`, error);
}
// 第二步:处理指定字段转为布尔值(0→false,1→true,NULL/其他→false)
booleanFields.forEach(field => {
const fieldValue = newItem[field];
// 处理"NULL"字符串、null、undefined → 转为false
if (fieldValue === "NULL" || fieldValue === null || fieldValue === undefined) {
newItem[field] = false
}else if (fieldValue === 0 || fieldValue === "0") {// 数字/字符串 0 → false;数字/字符串 1 → true
newItem[field] = false
}else if (fieldValue === 1 || fieldValue === "1") {
newItem[field] = true
}else {// 其他异常值(如2、"2")→ 默认为false(可根据需求调整)
newItem[field] = false
}
})
return newItem
})
}
purifyData(data) { //序列化一次用于修改数据报错
if (data === null || typeof data !== 'object') {
return data; // 基础类型直接返回
}
// 核心:通过JSON序列化+反序列化,过滤所有不支持的内容
try {
return JSON.parse(JSON.stringify(data));
} catch (error) {
console.error('数据净化失败,降级为浅拷贝:', error);
// 降级方案:手动浅拷贝(避免循环引用导致JSON序列化失败)
const pureObj = Array.isArray(data) ? [] : {};
for (const key in data) {
// 只处理自身属性,跳过原型链属性
if (Object.prototype.hasOwnProperty.call(data, key)) {
const value = data[key];
// 只保留基础类型、数组、纯对象
if (['string', 'number', 'boolean', 'null', 'undefined'].includes(typeof value)) {
pureObj[key] = value;
} else if (Array.isArray(value)) {
pureObj[key] = this.purifyData(value);
} else if (typeof value === 'object' && value !== null) {
pureObj[key] = this.purifyData(value);
}
}
}
return pureObj;
}
}
}
// 导出实例(全局单例)
export default new UniIndexedDB();
在使用地方调用
import indexedDB from '@/utils/groupChatDb' //链接创建
const res = await indexedDB.openDB()//打开并创键数据库
//使用
const resd = await indexedDB.deleteDataByConversationsId(res.data.group.id)
参考文章
[](https://blog.csdn.net/deku_ln/article/details/105431593)
[](https://cloud.tencent.com/developer/article/2541274)

浙公网安备 33010602011771号