今天想写一篇关于indexedDB的文章,由于最近项目需要前端存储数据,但是localStorage存储空间有限,最后综合考虑采用indexedDB来存储。本文将简单介绍一下indexedDB的使用场景,以及简单的封装。IndexedDB是一个基于JavaScript的面向对象数据库,他是一个事务型数据库系统,事务型数据库与关系型数据库的区别呢,这里就不多做介绍了。直接切入正文吧。
1、indexedDB的优点:
1. 键值对存储,方便。
2. 异步操作,不会导致主流程卡顿,影响用户体验。
3. 支持存储对象,字符串,二进制数据。
2、主要流程:
打开数据库( indexedDB.open() )>创建数据仓库( db.createObjectStore() )>创建一个事务,链接数据仓库( db.transaction([storeName]).objectStore(storeName) )>对数据增删改查( stroe.add()、store.put()、store.delete()、store.get() )>关闭数据库( db.close() )。
数据的获取方式有三种:
1、使用getAll()获取所有数据。
2、使用get(key)获取单条数据,这里的key是要获取数据的主键的值。
3、使用openCursor(),这是indexedDB的指针对象,他也是异步的所以监听success方法,然后使用cursor.contiune()移动指针。
3、封装:
interface MsgProps { type: string, message: string | object } export default class DB { dbName: string db: any constructor(name: string) { this.dbName = name } open(storeName: string, keyPath: string, indexs?: Array<string>) { if(!window.indexedDB) { return alert('您的浏览器不支持该app,为了更好的体验,请使用新版chrome浏览器') } const request = window.indexedDB.open(this.dbName, new Date().getTime()) return new Promise((resolve, rej) => { request.onerror = (e: any) => { this.onmessage({type: '数据库连接失败', message: e}) rej() } request.onsuccess = (e: any) => { this.db = e.target.result this.onmessage({type: '数据库连接成功', message: ''}) resolve() } request.onupgradeneeded = (e: any) => { const db = e.target.result if(!db.objectStoreNames.contains(storeName)) { const store = db.createObjectStore(storeName, {autoIncrement: true, keyPath}) if(indexs && indexs.length) { indexs.map((v) => { store.createIndex(v, v, { unique: false }) }) } store.transaction.oncomplete = (ev: any) => { this.onmessage({type: '创建对象仓库成功', message: ''}) } } } }) } onmessage(msg: MsgProps) { console.log(msg.type, msg.message) } update(storeName: string, data: object) { const store = this.db.transaction([storeName], 'readwrite').objectStore(storeName) return new Promise((resolve, rej) => { const request = store.put({ ...data, lastModify: new Date().getTime() }) request.onsuccess = (e: any) => { this.onmessage({ type: '更新成功', message: data }) resolve() } request.onerror = (e: any) => { this.onmessage({ type: '更新失败', message: data }) rej() } }) } getList(storeName: string) { const store = this.db.transaction([storeName]).objectStore(storeName) return new Promise((resolve, rej) => { store.getAll().onsuccess = (e: any) => { const res = e.target.result this.onmessage({ type: '获取列表成功', message: res }) resolve(res) } }) } getItem(storeName: string, key: string) { const store = this.db.transaction(storeName).objectStore(storeName) return new Promise((resolve, rej) => { const request = store.get(key) request.onsuccess = (e: any) => { resolve(e.target.result) } request.onerror = (e: any) => { rej() } }) } delete(storeName: string, key: string) { const store = this.db.transaction([storeName], 'readwrite').objectStore(storeName) const request = store.delete(key) return new Promise((resolve, rej) => { request.onsuccess = (e: any) => { this.onmessage({ type: '删除成功', message: key }) resolve() } request.onerror = (e: any) => { this.onmessage({ type: '删除失败', message: data }) rej() } }) } closeDB() { this.db.close() } deleteDB() { indexedDB.deleteDatabase(this.dbName) } }
如上所示,由于indexedDB的put会在没有找到的时候创建一条数据,找到的话更新这条数据。所以没有封装post方法。对于indexedDB来说没有数据表的概念,它是根据数据库版本号来管理对象残酷的。
注意:打开数据库的时候,只有版本号改变,才可以在该数据库中创建对象仓库。本人这里偷了个懒,直接使用时间戳作为版本号,请大家自行改进优化。