文章目录
- 往期回顾
- 项目实战
- 初始化表
- 获取列表
- 新增表的数据项
- 获取详情
- 根据ID获取详情
- 根据其他字段获取详情
- 删除数据
- 总结
往期回顾
在之前的文章中,我们介绍了IndexDB vs Cookies vs Session
这几个的对比,但是没有做实际项目的演示,今天我们用实际项目来演示IndexDB的便捷性。
首先需要明确的是IndexDB的适用场景:
- 离线应用
- 大型网页游戏
- 数据缓存
- 复杂数据管理和查询
项目实战
我们用纯IndexDB来实现表格的基本增删改查的功能!
这只是一个引子,实际上你可以将本示例的思想用于更大的场景
初始化表
按如下代码格式初始化IndexDB
,如果初始不存在,则创建表CryptSetting
(实际名称可自定义)和表的字段名,如下objectStore.createIndex()
方法。
创建表是最好声明一个自增的唯一主键id,本例为
projectId
let db = null;
// 初始化indexDB数据库
async function initDB() {const request = window.indexedDB.open('CryptSetting', 1);// success 事件表示成功打开数据库request.onsuccess = (event) => {db = event.target.result;// 打开成功之后需要获取数据库列表getList()};// error 事件表示打开数据库失败request.onerror = (event) => {console.log('打开 IndexedDB 失败');};// 如果指定的版本号,大于数据库的实际版本号,就会发生数据库升级事件 upgradeneededrequest.onupgradeneeded = function (e) {db = e.target.result;let objectStore;if ( !db.objectStoreNames.contains('CryptSetting') ) {// 索引名称、索引所在的属性、配置对象(说明该属性是否包含重复的值)objectStore = db.createObjectStore('CryptSetting', { keyPath: 'projectId', autoIncrement: true });objectStore.createIndex('project_name', 'projectName', { unique: false });objectStore.createIndex('key_1', 'key', { unique: false });objectStore.createIndex('iv_1', 'iv', { unique: false });}};
}
初始化之后,会在控制台看到如下:
获取列表
初始化之后,需要获取数据库列表
请注意以下的写法,列表只能一条条获取,可以先声明一个空数组接收,最后统一赋值
此处用到了continue
方法
效率还是很快的,不要以为一条条获取速度就慢!
// 获取配置列表
async function getList() {loading.value = trueconst transaction = db.transaction([ 'CryptSetting' ], 'readonly');const objectStore = transaction.objectStore('CryptSetting');const request = objectStore.openCursor(); // 获取所有配置// indexDB是一个个获取数据的,所以用数组接收,最后统一赋值const tempArr = []request.onsuccess = function (event) {const cursor = event.target.result;if (cursor) {tempArr.push(cursor.value);cursor.continue(); // 继续遍历下一条数据} else {tableData.value = tempArrloading.value = false}};request.onerror = function () {errorTip('获取列表失败')loading.value = false};
}
新增表的数据项
表初始化之后,其实还是空的表,所以上面获取值为空,所以此时需要往里面添加数据,按如下格式写即可。
注意:此处不传projectId,因为它是主键ID、会自动生成,按123456,
如果6被删除了,下次自动生成的ID为7
function addSettings() {const transaction = db.transaction([ 'CryptSetting' ], 'readwrite');const objectStore = transaction.objectStore('CryptSetting');const { projectName, key, iv } = formData.value // 此处不传projectId,自动生成const request = objectStore.add({projectName,key,iv});request.onsuccess = function (event) {successTip('添加成功')};request.onerror = function (event) {errorTip()};
}
新增之后,效果如下:
获取详情
根据ID获取详情
// 获取配置详情
function getSettingsDetail(id) {const transaction = db.transaction([ 'CryptSetting' ], 'readonly');const objectStore = transaction.objectStore('CryptSetting');const request = objectStore.get(id);request.onsuccess = function (event) {const result = event.target.result;if (result) {title.value = '编辑项目配置'isEdit.value = truedialogVisible.value = trueformData.value = result} else {errorTip('获取失败')}};request.onerror = function(event) {}
}
根据其他字段获取详情
在 IndexedDB 中,get 方法只能根据主键(keyPath)来查询数据。如果你需要根据其他字段(如 projectName、key、iv 等)来查询数据,可以使用索引(index)。索引允许你根据非主键字段来查询数据。
以下示例为:根据 projectName 查询配置详情
function getSettingsByProjectName(projectName) {console.log('projectName', projectName);const transaction = db.transaction(['CryptSetting'], 'readonly');const objectStore = transaction.objectStore('CryptSetting');const index = objectStore.index('project_name');const request = index.get(projectName);request.onsuccess = function (event) {const result = event.target.result;if (result) {title.value = '编辑项目配置';isEdit.value = true;dialogVisible.value = true;formData.value = result;} else {errorTip('获取失败');}};request.onerror = function (event) {console.error('查询失败', event);errorTip('查询失败');};
}
删除数据
// 删除配置,传参id
function deleteSettings(id) {const transaction = db.transaction([ 'CryptSetting' ], 'readwrite');const objectStore = transaction.objectStore('CryptSetting');const request = objectStore.delete(id); // 假设我们要删除id的记录request.onsuccess = function (event) {successTip('删除成功');};request.onerror = function (event) {errorTip('删除失败');};
}
总结
IndexDB的许多思想都和mysql有相似之处。
我们发现,基本上增删改查都有相似的代码
const transaction = db.transaction(['CryptSetting'], 'readwrite');const objectStore = transaction.objectStore('CryptSetting');
其实这段代码是不能省略的,因为它:
- 事务的独立性:
- 每个事务都是独立的,不能共享。一旦事务完成,就不能再使用它。
- 如果尝试在多个操作中重用同一个事务,会导致错误。
- 数据一致性:
- 每个事务确保数据的一致性。如果多个操作共享同一个事务,一个操作失败会导致整个事务回滚,影响其他操作。
- 错误隔离:
- 每个事务有自己的错误处理机制。如果一个事务失败,其他事务不会受到影响。
- 通过每次操作声明新的事务,可以更好地控制错误处理和回滚。
为了确保数据操作的正确性和一致性,每次进行新增、删除、更新等操作时都需要声明新的 transaction 和 objectStore。这是 IndexedDB 的设计原则,确保每个操作都是独立且可靠的。因此,不能省略每次操作时的 transaction 和 objectStore 声明。
以上仅为简易的入门,及细节讲解,更多细节需要实战中探索,感谢打赏!