IndexedDB设计及封装

发布时间 2023-11-21 11:15:00作者: 杜柯枫

设计思路

固定数据表

  • 键值对表
    用于存储数据库相关的信息
  • 库字段构成表
    储存非固定数据表结构

非固定数据表

通过库字段构成表进行创建或更新

划重点

  • 数据库初始创建或更新后会先触发onupgradeneeded方法,然后再触发onsuccess方法,如果在onupgradeneeded方法中执行了表结构操作的话,onsuccess会在transaction.oncomplete事件处理之后触发,所以在onsuccess方法中去执行增删改一定是在表完整结构基础上不必担心表错误

先上封装的代码

class indexedDBClass {
    db
    tableName
    keyPath
    // 连接数据库
    openDB(dbName) {
        return new Promise((resolve, reject) => {
            const request = indexedDB.open(dbName);
            // 创建或更新成功
            request.onupgradeneeded = (e) => {
                const db = e.target.result;
                this.initDB(db);
            };
            // 连接成功
            request.onsuccess = (e) => {
                resolve(e.target.result);
            };
            // 连接失败
            request.onerror = (e) => {
                reject(e.target.errorCode);
            };
        });
    }
    // 初始化数据库
    initDB(db) {
        this.keyPath = 'id'
        const objStore = db.createObjectStore(this.tableName, { keyPath: 'id' });
        objStore.createIndex('name', 'name', { unique: false })
    }
    // 插入一条数据
    putDataOnce(obj) {
        return new Promise((resolve, reject) => {
            let request = this.db.transaction([this.tableName], 'readwrite').objectStore(this.tableName).put(obj)
            request.onsuccess = function () {
                resolve()
            }
            request.onerror = function () {
                reject()
            }
        })
    }
    // 插入数据
    putData(list) {
        let arr = [].concat(list)
        return new Promise((resolve, reject) => {
            Promise.all(arr.map(v => this.putDataOnce(v)))
                .then(res => {
                    resolve()
                }).catch(err => {
                    reject()

                })
        })
    }
    // 通过主键删除数据
    delDataByKeyPath(keyPath) {
        return new Promise((resolve, reject) => {
            let request = this.db.transaction([this.tableName], 'readwrite').objectStore(this.tableName).delete(keyPath)
            request.onsuccess = function () {
                resolve()
            }
            request.onerror = function () {
                reject()
            }
        })
    }
    // 删除数据
    delData(obj) {
        // 由于只能通过主键删除数据,所以要先根据条件进行查询,后逐条进行删除操作
        return new Promise((resolve, reject) => {
            this.getData(obj).then(res => {
                return Promise.all(res.map(v => this.delDataByKeyPath(v.id)))
            }).then(res => {
                resolve()
            }).catch(err => {
                reject()
            })
        })
    }
    // 获取数据
    getData(obj) {
        const objectStore = this.db.transaction(this.tableName).objectStore(this.tableName);
        let objKeyList = Object.keys(obj)
        return new Promise((resolve, reject) => {
            let arr = []
            objectStore.openCursor().onsuccess = ({ target: { result } }) => {
                if (result) {
                    if (objKeyList.every(v => obj[v] === result.value[v])) {
                        arr.push(result.value)
                    }
                    result.continue();
                } else {
                    resolve(arr)
                }
            }
        })
    }
    // 构造方法
    constructor(tableName, cb, dbName = '***') {
        this.tableName = tableName;
        this.openDB(dbName).then((res) => {
            this.db = res;
            cb()
        });
    }
}

使用的时候先创建数据库表

collegeDB = new indexedDBClass('college', () => {
    // 这里的'college'是表名,数据库名默认为'***',可以传第三个参数更换数据库名
    // 使用数据库的代码都要在这里面运行,不然会出现数据库未链接就使用的情况
    // 获取数据(参数是匹配条件)
    let list = await collegeDB.getData({ name: '张三' })
    // 新增&插入数据(参数是完整的要存储的数据)
    await collegeDB.putData(list)
    // 删除数据(参数是匹配条件)
    await collegeDB.delData({ name: '张三' })
})

整个使用下来给我一种就是把数据存在本地的错觉,而且相当不好用,特别是批量处理相当不友好,对于布尔值的搜索还会报错(所以获取数据变成获取全部数据再用js匹配筛选),个人感觉自己写页面玩一玩就得了,要不是谷歌不支持websql我是真的不想研究这玩意