简单封装一下indexedDB

index.js(数据库的封装)


/**
 * IndexedDB
 */
const IndexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;

/**
 * 数据库结构
 * 对象空间
 */
const IDB_STRUCTURE = [
    // 客户端配置
    {
        IDB_STORE_NAME: "表名",
        IDB_STORE_OPTIONS: { keyPath: '主键字段', autoIncrement: false },
        IDB_STORE_INDEX: [
            // 主键 
            { name: "主键字段名", prop: "属性名", options: { unique: true } },
            { name: "其它字段", prop: "属性名", options: { unique: false } },
        ]
    }
];

/**
 * IDBInstence
 * @class IDBInstence
 * @description IDBInstence
 */
class IDBInstence {
    /**
     * 构造函数
     */
    constructor(IDB_NAME = null) {
        /**
         * 数据库名称
         */
        this.IDB_NAME = IDB_NAME || null;
        /**
         * 数据库版本
         */
        this.IDB_VERSION = null;
        /**
         * 数据库实例
         */
        this.IDB_DATABASE = null;
        /**
        * 是否就绪
        */
        this.IDB_READY = false;
    }

    /**
     * 初始化数据库
     * @param {string} IDB_NAME 
     */
    initialization(IDB_NAME = null) {
        return new Promise((resolve, reject) => {

            // 数据库名称
            if (!!IDB_NAME) this.IDB_NAME = IDB_NAME;

            // 是否支持indexedDB
            if (!!IndexedDB === false) return reject("IndexedDB is not supported.");

            // 是否已经开启
            if (this.IDB_READY) return resolve();

            // 打开数据库
            let request = IndexedDB.open(this.IDB_NAME, this.IDB_VERSION || undefined);

            // 打开成功
            request.onsuccess = events => {
                // 数据库对象
                this.IDB_DATABASE = events.target.result;

                // 检查是否有不存在的对象空间
                if (IDB_STRUCTURE.findIndex(element => !!this.IDB_DATABASE.objectStoreNames.contains(element.IDB_STORE_NAME) === false) !== -1) {
                    // 数据库版本升级
                    this.IDB_VERSION = this.IDB_DATABASE.version + 1;
                    // 关闭当前连接
                    this.IDB_DATABASE.close();
                    // 置空对象
                    this.IDB_DATABASE = null;
                    // 回调连接并创建对象空间
                    this.initialization(IDB_NAME).then(resolve).catch(reject);
                } else {
                    this.IDB_READY = true;
                    resolve();
                }
            };

            // 打开失败
            request.onerror = events => (this.IDB_DATABASE = events.target, reject(events.target));

            // 创建对象仓库
            request.onupgradeneeded = events => {
                // 遍历创建
                for (let index = 0; index < IDB_STRUCTURE.length; index++) {
                    // 当前对象
                    let element = IDB_STRUCTURE[index];
                    // 检查对象空间是否存在
                    if (!!events.currentTarget.result.objectStoreNames.contains(element.IDB_STORE_NAME)) continue;
                    // 创建并创建主键(idbid)自增
                    let store = events.currentTarget.result.createObjectStore(element.IDB_STORE_NAME, element.IDB_STORE_OPTIONS);
                    // 创建字段索引
                    element.IDB_STORE_INDEX.forEach(itemIndex => store.createIndex(itemIndex.name, itemIndex.prop, itemIndex.options));
                }
            };
        });
    }

    /**
     * 获取表格结构
     * @param {*} IDB_STORE_NAME 表名
     */
    obtainTableStructure(IDB_STORE_NAME) {
        return IDB_STRUCTURE[IDB_STRUCTURE.findIndex(table => table.IDB_STORE_NAME === IDB_STORE_NAME)];
    }
}

/**
 * IDBInstence
 * new instence
 */
const Instence = new IDBInstence();

/**
 * 输出模块
 */
export default Instence;

table.js(表格封装)

数据操作

/**
 * IDBInstence
 */
import IDBInstence from "./index";

/**
 * IDBKeyRange
 */
const IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;

/**
 * 数据库结构
 * 对象空间
 */
class TableInstence {
    /**
     * 构造函数
     */
    constructor(IDB_STORE_NAME = null) {
        /**
         * 对象仓库名称
         */
        this.IDB_STORE_NAME = IDB_STORE_NAME || null;

        /**
         * 是否就绪
         */
        this.IDB_READY = IDBInstence.IDB_READY;
    }

    /**
     * 创建服务
     * @param model 模式
     */
    createService(model = "readonly") {
        return IDBInstence.IDB_DATABASE.transaction(this.IDB_STORE_NAME, model).objectStore(this.IDB_STORE_NAME);
    }

    /**
     * 插入一条数据
     * @param {Object} data 
     * @returns 
     */
    insert(data = {}) {
        return new Promise((resolve, reject) => {
            // 创建事务
            let request = this.createService('readwrite').add(data);
            // 插入成功
            request.onsuccess = events => resolve(events.target.result);
            // 插入失败
            request.onerror = () => reject(request.error);
        });
    }

    /**
     * 根据主键的值查询数据
     * @param {*} idbid 主键的值
     * @returns 
     */
    find(idbid = 0) {
        return new Promise((resolve, reject) => {
            // 创建事务
            let request = this.createService('readonly').get(idbid);
            // 查询成功
            request.onsuccess = () => !!request.result ? resolve(request.result) : reject(`No data with a primary key of "${idbid}" was found in the "${this.IDB_STORE_NAME}" table`);
            // 查询失败
            request.onerror = () => reject(request.error);
        });
    }

    /**
     * 根据索引的值查询数据
     * @param {*} index 索引
     * @param {*} value 索引的值
     * @returns 
     */
    findIndex(index = null, value = null) {
        return new Promise((resolve, reject) => {
            // 创建事务
            let request = this.createService('readonly').index(index).get(value);
            // 查询成功
            request.onsuccess = events => !!events.target.result ? resolve(events.target.result) : reject(`Data with an index(${index}) value of "${value}" was not found in the "${this.IDB_STORE_NAME}" table`);
            // 查询失败
            request.onerror = () => reject(request.error);
        });
    }

    /**
     * 查询全部数据
     * @returns 
     */
    findAll() {
        return new Promise((resolve, reject) => {
            // 创建事务
            let request = this.createService('readonly').getAll();
            // 查询成功
            request.onsuccess = events => resolve(events.target.result);
            // 查询失败
            request.onerror = () => reject(request.error);
        });
    }

    /**
     * 根据条件获取数据
     * @param {Object} parameters { current: 页码, size: 页大小, index: "索引", value: "索引值", filters: row => true }
     * @returns 
     */
    findAllByFilters(parameters = { current: 1, size: 10, index: null, value: null, filters: row => true }) {
        return new Promise((resolve, reject) => {
            let options = { current: 1, size: 10, index: null, value: null, filters: row => true };
            // 校验页码
            if (!!parameters?.current && isFinite(parameters?.current)) options.current = parameters.current;
            else return reject(`Your page parameter "current" is not a valid page number`);
            // 校验大小
            if (!!parameters?.size && isFinite(parameters?.size)) options.size = parameters.size;
            else return reject(`Your page parameter "size" is not a valid page size number`);
            // 校验索引
            if (parameters?.index !== null && parameters?.index !== undefined) options.index = `${parameters.index}`;
            // 校验索引值
            if (parameters?.value !== null && parameters?.value !== undefined) options.value = parameters.value;
            // 校验过滤方法
            if (typeof parameters?.filters === "function") options.filters = parameters.filters;

            // 创建事务
            let request = null;
            if (!!options.index) request = this.createService().index(options.index).openCursor(IDBKeyRange.only(options.value));
            else this.createService().openCursor();

            // 响应数据
            let response = {
                // 当前页
                current: options.current,
                // 一页大小
                size: options.size,
                // 总条数
                total: 0,
                // 数据列表
                list: []
            };

            // 开始下标
            let previous = (options.current - 1) * options.size;
            // 结束下标
            let behind = previous + options.size - 1;

            // 查询成功
            request.onsuccess = events => {
                // 请求数据
                let result = events.target.result;
                // 是否有数据
                if (!!result) {
                    // 是否满足条件
                    if (options.filters(result.value)) {
                        // 添加到响应
                        if (response.total >= previous && response.total <= behind) response.list.push(result.value);
                        // 增加条数
                        response.total += 1;
                    }
                    // 下一条
                    result.continue();
                } else resolve(response);
            };

            // 查询失败
            request.onerror = () => reject(request.error);
        });
    }

    /**
     * 根据主键的值删除数据
     * @param {*} idbid 主键的值
     * @returns 
     */
    delete(idbid = 0) {
        return new Promise((resolve, reject) => {
            // 创建事务
            let request = this.createService('readwrite').delete(idbid);
            // 查询成功
            request.onsuccess = () => resolve(request.result);
            // 查询失败
            request.onerror = () => reject(request.error);
        });
    }

    /**
     * 根据索引的值删除数据
     * @param {*} index 索引
     * @param {*} value 索引的值
     * @returns 
     */
    deleteIndex(index = null, value = null) {
        return new Promise((resolve, reject) => this.findIndex(index, value).then(result => this.delete(result[IDBInstence.obtainTableStructure(this.IDB_STORE_NAME)?.IDB_STORE_OPTIONS.keyPath])).then(resolve).catch(reject));
    }

    /**
     * 根据主键更新数据
     * @param {*} idbid 主键 
     * @param {*} data 更新的值
     * @returns 
     */
    update(idbid = 0, data = {}) {
        return new Promise((resolve, reject) => this.find(idbid).then(result => {
            // 新数据
            let newData = JSON.parse(JSON.stringify(Object.assign(result, data)));
            // 创建事务
            let request = this.createService("readwrite").put(newData);
            // 查询成功
            request.onsuccess = () => resolve(newData);
            // 查询失败
            request.onerror = () => reject(request.error);
        }).catch(reject));
    }

    /**
     * 根据索引的值更新数据
     * @param {*} index 主键 
     * @param {*} value 索引的值 
     * @param {*} data 更新的值
     * @returns 
     */
    updateIndex(index = null, value = null, data = {}) {
        return new Promise((resolve, reject) => this.findIndex(index, value).then(result => {
            // 新数据
            let newData = JSON.parse(JSON.stringify(Object.assign(result, data)));
            // 创建事务
            let request = this.createService("readwrite").put(newData);
            // 查询成功
            request.onsuccess = () => resolve(newData);
            // 查询失败
            request.onerror = () => reject(request.error);
        }).catch(reject));
    }
}

/**
 * 单例模式
 * @returns
 */
let InstanceMode = IDB_STORE_NAME => new Proxy(new TableInstence(IDB_STORE_NAME), {
    /**
     * get
     * @param {*} target 
     * @param {*} prop 
     * @param {*} receiver 
     * @returns 
     */
    get(target, prop, receiver) {
        // 拦截方法调用
        if (typeof target[prop] === 'function') return function (...args) {
            // 调用之前判断数据库是否就绪
            if (!!IDBInstence.IDB_READY === false) return Promise.reject("IDBInstence is not ready.");
            const result = target[prop].apply(target, args);
            // 调用之后 
            // ()=>{}
            return result;
        };
        // 如果不是方法调用,则直接返回原始属性
        else return Reflect.get(target, prop, receiver);
    }
});

/**
 * 输出模块
 * 拦截器
 */
export default InstanceMode;

使用

/**
 * 数据库
 */
import IDBInstence from "./index";
/**
 * 表格
 */
import IDBTable from "./table";

/**
 * 初始化数据库
 */
IDBInstence.initialization("captaintwo").then(() => {

    console.log("数据库初始化成功!");

    // 创建表格实例
    let table = IDBTable("表名");

    // 插入数据
    table.insert({ ... }).then(response => {
        console.log("数据插入成功!", response);
    }).catch(error => {
        console.error("数据插入失败!", error);
    });
    
}).catch(error => {
    console.error("数据库初始化失败!", error);
});
文章作者: CaptainTwo
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 CaptainTwo
前端 JavaScript
喜欢就支持一下吧