indexDB的使用

简介

IndexedDB 是一种可以让你在用户的浏览器内持久化存储数据的方法。IndexedDB 为生成 Web Application 提供了丰富的查询能力,使我们的应用在在线和离线时都可以正常工作。

无法开启indexDb的情况

  1. 浏览器不希望允许某些广告网络或恶意网站来污染你的计算机,所以浏览器会在任意给定的 web app 首次尝试打开一个 IndexedDB 存储时对用户进行提醒。用户可以选择允许访问或者拒绝访问。
  2. IndexedDB 在浏览器的隐私模式(Firefox 的 Private Browsing 模式和 Chrome 的 Incognito 模式)下是被完全禁止的。

开始使用

打开数据库

首先要判断浏览器是否支持支持indexDb,之后在打开,并生成错误处理函数

let indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
if (!indexedDB) {
    console.log("浏览器不支持indexedDB");
}
// 打开我们的数据库,使用open方法
let request = indexedDB.open("MyTestDatabase");
// 错误处理,onerror函数
request.onerror = function (event) {
    console.log("error", event);
};

为该数据库创建一个对象仓库

假设我们需要存储用户信息,信息格式为{id:1,name:"张三",email:"1@qq.com"}。那么我们吧仓库命名为"userInfo"
当你创建一个新的数据库或者增加已存在的数据库的版本号, onupgradeneeded 事件会被触发

// 接上面的代码
request.onupgradeneeded = function (event) {
    var db = event.target.result;
    // 为该数据库创建一个对象仓库,创建一个名为“userInfo”的仓库,并指定id作为键路径(keyPath)
    var objectStore = db.createObjectStore("userInfo", {keyPath: "id"});
    // 建立一个索引来通过姓名来搜索客户。名字可能会重复,所以我们不能使用 unique 索引
    objectStore.createIndex("name", "name", {unique: false});
    // 使用邮箱建立索引,我们向确保客户的邮箱不会重复,所以我们使用 unique 索引
    objectStore.createIndex("email", "email", {unique: true});
};

createObjectStore(name, options)函数接收两个参数,第一个参数为仓库的名字,第二个参数是个对象,是可选参数,其中包括以下的属性:

  1. keyPath:指定键路径,需要唯一,可以不指定
  2. autoIncrement:boolean类型,键生成器,是否自动生成,默认false

createIndex(name,keypath,options)接受三个参数
name:索引的名称,可为空
keypath:索引对应的keyPath
options:可选,参数为:

  1. unique:boolean类型,如果为 true,则索引将不允许单个键的重复值。
  2. multiEntry:boolean类型,如果true,则当keyPath解析为数组时,索引将在每个数组元素的索引中添加一个条目。如果 false,它将添加一个包含数组的条目。
  3. locale:目前仅限 Firefox (43+),为索引指定语言环境

新增数据

上面已经创建好数据库和表了,数据库名:MyTestDatabase,表名:userInfo,浏览器打开F12,Application->IndexDB即可看到,接下来我们为表中增加100条数据。
首先我们先自己造100条数据:

let arr = [];
for (let i = 0; i < 100; i++) {
    arr.push({
        id: i,
        name: "张" + i,
        email: i + "@qq.com"
    });
}

之后新增到userInfo表中:

request.onsuccess = function (event) {
    db = event.target.result;
    var transaction = db.transaction(["userInfo"], "readwrite");
    var objectStore = transaction.objectStore("userInfo");
    for (let i of arr) {
        objectStore.add(i);
    }
};

transaction(storeNames, mode, options)表示一个事务。在数据库上创建一个事务,指定作用域(例如要访问的存储对象),并确定所需的访问类型(只读或读写)。接收三个参数:
storeNames:字符串数组,对象库名称,如果只有一个,也可以写字符串不写数组
mode:字符串,可选参数。readonly和readwrite,默认为readonly,表示只读,readwrite表示可以写入。除此之外还有个只用于Firefox的“readwriteflush”,目前实验性的。
options:可选参数,durability: “default”, “strict”, 或 “relaxed”。默认值为"default"。"relaxed"提供了更好的性能,"relaxed"用于临时数据。

objectStore()表示允许访问通过主键查找的 IndexedDB 数据库中的一组数据的对象存储区。为了方便理解,可以把“对象存储空间”想象成关系数据库的“表”结构,下文也会把对象存储空间称为表。

查找数据

可以使用get方法查找到某一条数据

request.onsuccess = function (event) {
    db = event.target.result;
    var transaction = db.transaction(["userInfo"]);
    var objectStore = transaction.objectStore("userInfo");
    let men1 = objectStore.get(2);
    men1.onsuccess = function (e) {
        var data = e.target.result;
        console.log(data);
    };
};

使用索引查询

有时候我们并不能确定用户的id,只能通过其他方式去查找,比如我们想查找邮箱为"5@qq.com"的用户,这时候就需要用到索引。
使用索引之前必须确定已经设置了索引,在创建表的时候,我们通过 objectStore.createIndex("email", "email", {unique: true});设置了email的索引

request.onsuccess = function (event) {
    db = event.target.result;
    var transaction = db.transaction(["userInfo"]);
    var objectStore = transaction.objectStore("userInfo");
    let men1 = objectStore.index("email");
    // 查找邮箱为‘5@qq.com’的用户
    men1.get('5@qq.com').onsuccess = function (e) {
        var data = e.target.result;
        console.log(data);
    };
};

index()方法参考objectStore方法一览

使用游标查询

游标的使用方法:

request.onsuccess = function (event) {
    db = event.target.result;
    var transaction = db.transaction(["userInfo"]);
    var objectStore = transaction.objectStore("userInfo");
    let men1 = objectStore.openCursor();
    men1.onsuccess = function (e) {
        var data = e.target.result;
        if (data) {
            console.log(data.value);
            data.continue(); // 使游标下移
        } else {
            console.log("No more entries!");
        }
    };
};

如果我们要查询id 5-9的数据,不包含5,但包含9

    let men1 = objectStore.openCursor(IDBKeyRange.bound(5,9,true, false));
    let list=[]
    men1.onsuccess = function (e) {
        var data = e.target.result;
        if (data) {
            list.push(data.value)
            data.continue(); // 使游标下移
        } else {
            console.log("No more entries!");
        }
        console.log(list); // 打印出id是6 7 8 9的数据
    };

修改数据

使用get方法找到数据并指定为“readwrite”进行修改

request.onsuccess = function (event) {
    db = event.target.result;
    var transaction = db.transaction(["userInfo"], "readwrite");
    var objectStore = transaction.objectStore("userInfo");
    let men1 = objectStore.get(1);
    men1.onsuccess = function (e) {
        // 获取我们想要更新的数据
        var data = e.target.result;
        data.name="张三2"
        console.log(data)
        objectStore.put(data)
    };
};

删除数据

通过delete方法删除

request.onsuccess = function (event) {
    db = event.target.result;
    var transaction = db.transaction(["userInfo"], "readwrite");
    var objectStore = transaction.objectStore("userInfo");
    let men1 = objectStore.delete(1);
    men1.onsuccess = function (e) {
        console.log("删除成功")
        console.log( e)
    };
};

objectStore方法一览:

方法名参数作用
add(value,key)value:被存储的值.key:标识某条记录的键,如果不指定,它会被设为null添加一条数据。
clear()清除表
count(key)key:键或键范围(key range计算符合条件的对象的数量
createIndex(name,keyPath,optional)*详见上方为该数据库创建一个对象仓库创建并返回新的IDBIndex对象,该方法只能从versionchange事务模式的回调方法中被调用
delete(key)key:标识记录的键或键范围从表中删除数据
deleteIndex(indexName)indexName:要删除的现有索引的名称删除索引,该方法只能在VersionChange监听函数里面调用。
get(key)key:键或键范围从表中检索请求的记录(只返回一条)
index(name)name:要打开的索引的名称打开此表中的命名索引
openCursor(range,direction)range:用作游标范围的键范围。如果此参数未指定或为空,则该范围包括对象存储中的所有记录。direction:游标的方向,包括:“next”(显示所有记录,包括重复记录,从下往上移动),“nextunique”(显示所有记录,不包括重复项,从下往上移动),“prev”(显示所有记录,包括重复记录,从上往下移动),“prevunique”(显示所有记录,不包括重复记录,从上往下移动)获取一个指针对象
openKeyCursor(range, direction)同上获取一个主键指针对象
put(value,key)value:新数据,key:主键,可为空更新某个主键对应的数据记录,如果对应的键值不存在,则插入一条新的记录
getKey(key)key:主键值或 IDBKeyRange 对象获取主键
getAll(query, count)query:键或IDBKeyRange,可选,count:返回值的数量,可选获取对象仓库的记录
getAllKeys(query, coun)同上获取所有符合条件的主键

简单封装

原生的indexDB语法比较繁琐,把上面的代码稍微封装一下,方便调用

let indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;

class DB {
    constructor(name, version, options) {
        this._dbs = {};
        this._databaseName = name;
        this.currentStore = "";
        this.open(name, version, options);
    }

    open(name, version, options) {
        if (!indexedDB) {
            console.error("浏览器不支持indexedDB");
            return;
        }
        return new Promise((resolve, reject) => {
            if (this._dbs && this._dbs[name]) {
                resolve(this._dbs[name]);
                return;
            }
            let request = indexedDB.open(name, version);
            request.onupgradeneeded = (event) => {
                let db = event.target.result;
                this._dbs[name] = db;
                for (let i in options) {
                    // 判断是否存在表
                    if (!db.objectStoreNames.contains(options[i].storeName)) {
                        var objectStore = db.createObjectStore(options[i].storeName, options[i].option);
                        for (let j of options[i].index) {
                            objectStore.createIndex(j.name, j.keyPath, {unique: j.unique});
                        }
                    }
                }
                resolve(db);
            };
            request.onsuccess = (event) => {
                // IDBDatabase
                const db = event.target.result;
                // 缓存起来
                this._dbs[name] = db;
                resolve(db);
            };
            request.onerror = (event) => {
                reject(event);
                console.error('IndexedDB', event);
            };
        });
    }

    async _getTransaction(storeName, version) {
        let db;
        // 先从缓存获取
        if (this._dbs[this._databaseName]) {
            db = this._dbs[this._databaseName];
        } else {
            db = await this.open(this._databaseName, version);
        }
        return db.transaction([storeName], 'readwrite');
    }

    async _getObjectStore(storeName, version) {
        let transaction = await this._getTransaction(storeName, version);
        return transaction.objectStore(storeName);
    }

    // 获取一个store
    collection(storeName, version) {
        this.currentStore = storeName;
        this._getObjectStore(storeName, version);
        return this;
    }

    add(data) {
        return new Promise((resolve, reject) => {
            this._getObjectStore(this.currentStore).then((objectStore) => {
                const request = objectStore.add(data);
                request.onsuccess = function (event) {
                    resolve(event.target.result);
                };
                request.onerror = (event) => {
                    reject(event);
                };
            });
        });
    }

    get(data) {
        return new Promise((resolve, reject) => {
            this._getObjectStore(this.currentStore).then((objectStore) => {
                const request = objectStore.get(data);
                request.onsuccess = function (event) {
                    resolve(event.target.result);
                };
                request.onerror = (event) => {
                    reject(event);
                };
            });
        });
    }

    delete(data) {
        return new Promise((resolve, reject) => {
            this._getObjectStore(this.currentStore).then((objectStore) => {
                const request = objectStore.delete(data);
                request.onsuccess = function (event) {
                    resolve(event.target.result);
                };
                request.onerror = (event) => {
                    reject(event);
                };
            });
        });
    }

    clear(data) {
        return new Promise((resolve, reject) => {
            this._getObjectStore(this.currentStore).then((objectStore) => {
                const request = objectStore.clear(data);
                request.onsuccess = function (event) {
                    resolve(event.target.result);
                };
                request.onerror = (event) => {
                    reject(event);
                };
            });
        });
    }

    put(data) {
        return new Promise((resolve, reject) => {
            this._getObjectStore(this.currentStore).then((objectStore) => {
                const request = objectStore.put(data);
                request.onsuccess = function (event) {
                    resolve(event.target.result);
                };
                request.onerror = (event) => {
                    reject(event);
                };
            });
        });
    }

    find(start,end,startInclude,endInclude){
        return new Promise((resolve, reject) => {
            this._getObjectStore(this.currentStore).then((objectStore) => {
                const request = objectStore.openCursor(IDBKeyRange.bound(start,end,startInclude, endInclude));
                request.onsuccess = function (event) {
                    resolve(event.target.result);
                };
                request.onerror = (event) => {
                    reject(event);
                };
            });
        });

    }

	// 还可以根据自己需求继续写
}

使用方法:

    let data = [];
    for (let i = 0; i < 100; i++) {
        data.push({
            id: i,
            name: "张" + i,
            email: i + "@qq.com"
        });
    }
    let option = [
        {
            storeName: "test1",
            option: {
                keyPath: "id"
            },
            index: [{
                name: 'id', keyPath: "id", unique: true
            }, {
                name: 'name', keyPath: "name", unique: false
            }, {
                name: 'emial', keyPath: "emial", unique: true
            }]
        }
    ];
    let db = new DB("myTest", "1", option);
    const store = db.collection('test1',"1");
    store.add(data[0]);
    store.get(data[0].id).then((result) => {
        console.log(result);
    });
    store.add(data[1]);
    store.add(data[2]);
    store.delete(data[0].id)

indexDB库

在实际开发中我们可能更倾向于使用现成的轮子,比如

  1. dexie.js:IndexedDB 的包装,通过简单的语法,可以更快地进行代码开发。缺点是官方文档只有英文的
  2. IndexDBWrapper:有中文文档,对indexDB的简单封装,方法较少

大家可以根据实际需求选择自己封装还是直接使用现成的库。

  • 15
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值