关于indexedDB的使用
一. indexedDB是什么
1.概念
IndexedDB 是一种在浏览器中用于存储大量结构化数据的 NoSQL 数据库
2.特点
存储量大
支持复杂数据结构,能够存储对象和二进制数据,并且可以使用索引来快速检索数据
异步操作
持久性存储
3. 使用场景
离线应用: 可以存储应用所需的数据,以便在离线状态下使用。例如,离线邮件客户端可以将邮件存储在 IndexedDB 中,以便用户在没有网络连接时也能查看邮件。
缓存数据:可以缓存服务器端的数据,以减少网络请求和提高应用的性能。例如,新闻应用可以将最近的新闻文章存储在 IndexedDB 中,以便用户在下次访问时能够更快地加载。
二. 一些概念
1. 基本的操作
IndexedDB 鼓励使用的基本模式如下所示:
打开数据库。
在数据库中创建一个对象存储(object store)。
启动事务,并发送一个请求来执行一些数据库操作,如添加或获取数据等。
通过监听正确类型的 DOM 事件以等待操作完成。
对结果进行一些操作(可以在 request 对象中找到)
2. 概念
(1)数据库 (database):IndexedDB 的数据库是相关数据的容器,每个域名可以创建多个数据库。数据库有版本控制,结构修改(如新增或删除表、索引)只能通过升级版本完成。
(2)对象存储 (object store):IndexedDB 使用对象存储而不是表,并且一个数据库可以包含任意数量的对象存储
(3)事务 (transaction):你需要开启一个事务才能对你创建的数据库进行操作。事务来自于数据库对象,而且你必须指定你想让这个事务跨越哪些对象存储。一旦你处于一个事务中,你就可以访问用于保存数据的对象存储
所有数据操作都在事务中进行,以确保数据的一致性和完整性。事务对象提供了error,abort,complete三个回调方法,监听操作结果。
事务提供了三种模式:readonly、readwrite 和 versionchange。
使用 readonly 或 readwrite 模式都可以从已存在的对象存储里读取记录。但只有在 readwrite 事务中才能修改对象存储。
必须在 versionchange 事务中才能修改数据库的“模式”或结构(包括新建或删除对象存储、索引)(此功能在web workers中可用)。
(4)索引(index):索引用于加速数据检索。每个对象存储可以为不同属性建立索引。
(5)游标(cursor):IDBCursor 对象, 游标用于遍历对象存储中的记录,支持从指定位置开始读取数据,并进行数据的批量操作。
总结: 一个indexedDB 可以有多个数据库,一个数据库有多个对象存储.
数据库开启的操作事务需要指定对象存储,然后进行访问。
三. 简单的封装使用
可以先看MDN给的例子,正常跑通基本逻辑,然后再根据自己的需求封装下。下面的indexedDB.js是工具类,vue文件是调用情况
目的:
给一个key和obj,实现数据的新增,能通过这个key查询,删除,修改
方案:
新增的时候,利用key作为对象存储的键路径, { [key]: key, value: obj}
查询的时候利用get()
删除的时候也通过这个key
修改的也是重置这个
// indexedDB.js
class IndexdedDB {
constructor (name = 'custom', version = 1) {
this.request = null
this.db = null
this.name = name
this.version = version
}
// 因为获取数据库是异步操作,所以用promise封装下
getDb (key) {
return new Promise((resolve, reject) => {
if (this.db) {
resolve()
return
}
// 打开数据库
this.request = window.indexedDB.open(this.name, this.version)
// 打开数据库的时候就应该创建对象存储
this.request.onsuccess = (event) => { // 貌似用这个不行
console.log('获取数据库成功')
this.db = event.target.result
resolve()
}
// 当你创建一个新的数据库或者增加已存在的数据库的版本号
this.request.onupgradeneeded = (event) => {
console.log('新建数据库成功')
this.db = event.target.result
this.objectStore = this.db.createObjectStore(key, { keyPath: key })
this.objectStore.transaction.oncomplete = (event) => {
console.log('对象存储已经存在')
}
}
this.request.onerror = (event) => {
// 针对此数据库请求的所有错误的通用错误处理器!
console.error(`数据库错误:${event.target.errorCode}`)
reject(new Error(`数据库错误:${event.target.errorCode}`))
}
})
}
// 新增数据, 用Key做为对象存储名字, 和keyPath
async addData (key, data) {
try {
await this.getDb(key)
const newData = {
[key]: key,
value: JSON.stringify(data)
}
// 先判断有没有在对象存储中,有的话就更新
const res = await this.getData(key)
if (res) {
this.editData(key, newData)
return
}
// 将数据保存到新创建的对象存储中。
const customerObjectStore = this.db
.transaction(key, 'readwrite')
.objectStore(key)
console.log('customerObjectStore', customerObjectStore)
const addRequest = customerObjectStore.add(newData)
addRequest.onsuccess = function () {
console.log('Data added successfully:', newData)
}
addRequest.onerror = function (event) {
console.log('Error adding data:', event.target.errorCode)
}
} catch (error) {
}
}
// 获取数据
async getData (key) {
return new Promise(async (resolve, reject) => {
await this.getDb()
const transaction = this.db.transaction([key])
const objectStore = transaction.objectStore(key)
// 使用 get() 要求你知道你想要检索哪一个键
const request = objectStore.get(key)
request.onerror = (event) => {
// 错误处理!
reject(new Error('获取失败'))
}
request.onsuccess = (event) => {
console.log('request.result', request.result)
// 对 request.result 做些操作!
request.result ? resolve(JSON.parse(request.result.value)) : resolve(null)
}
})
}
async editData (key, newData) {
const objectStore = this.db
.transaction([key], 'readwrite')
.objectStore(key)
const request = objectStore.get(key)
request.onerror = (event) => {
// 错误处理!
}
request.onsuccess = (event) => {
console.log('objectStore', objectStore)
// 把更新过的对象放回数据库。
const requestUpdate = objectStore.put(newData)
requestUpdate.onerror = (event) => {
// 对错误进行处理
}
requestUpdate.onsuccess = (event) => {
// 成功,数据已更新!
console.log('成功,数据已更新!', event)
}
}
}
async delData (key) {
await this.getDb()
const request =
this.db.transaction([key], 'readwrite')
.objectStore(key)
.delete(key)
return new Promise((resolve, reject) => {
request.onsuccess = (event) => {
// 删除成功!
console.log('删除成功')
resolve()
}
request.onerror = function (event) {
console.log('数据删除失败')
reject(new Error('删除失败'))
}
})
}
}
const indexedDB = new IndexdedDB()
export default indexedDB
<template>
<div>
<el-button type="primary" @click="operation.add">新增</el-button>
<el-button type="primary" @click="operation.view">查看</el-button>
<el-button type="primary" @click="operation.del">删除</el-button>
<el-button type="primary" @click="operation.edit">编辑</el-button>
</div>
</template>
<script>
import indexedDB from '@/utils/indexedDB'
export default {
data () {
return {
operation: {
add: this.add,
view: this.view,
edit: this.edit,
del: this.del
}
}
},
methods: {
add () {
console.log('add')
indexedDB.addData('a', {
a: 'qiang'
})
},
view () {
console.log('view')
indexedDB.getData('a').then(res => {
console.log('res', res)
})
},
edit () {
console.log('edit')
indexedDB.addData('a', { b: 'xiang' }).then(res => {
console.log('res', res)
})
},
del () {
console.log('del')
indexedDB.delData('a').then(res => {
console.log('删除成功')
})
}
}
}
</script>
<style>
</style>