前面說過html5對于離線應(yīng)用的支持是很好的,不禁支持localstorage這樣在客戶端存儲一個鍵值對的方式而且還可以引用manifest文件,將需要緩存的文件在其中定義,其實html5中還可以使用indexdb,又稱索引數(shù)據(jù)庫,該數(shù)據(jù)庫可以用來存儲離線對象。下面開始:
請求完成后的回調(diào)
所有的請求完成之后都會有一個回調(diào),onsuccess 和onerror,其中:onsuccess表示請求成功時候的回調(diào),onerror 表示請求失敗時候的回調(diào)。同時還可以使用javascript中的 try/catch來捕獲異常,在進(jìn)一步的處理。
使用數(shù)據(jù)庫
一個數(shù)據(jù)庫一次只能有一個版本,初次創(chuàng)建改數(shù)據(jù)庫的時候版本號是0,當(dāng)我們需要更改已經(jīng)創(chuàng)建好的數(shù)據(jù)庫時候,就需要更改其版本號,當(dāng)更改 版本號的時候,會觸發(fā)upgradeneeded回調(diào),所以修改數(shù)據(jù)庫或者存儲對象的方法必須放到upgradeneeded方法中執(zhí)行。
判斷當(dāng)前瀏覽器是否支持indexdb
if (!window.indexedDB) { window.alert("您的瀏覽器不支持indexdb"); }<!--這里indexDB是window對象的屬性,類似于alert所以window可以省略-->
創(chuàng)建數(shù)據(jù)庫
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Document</title> <script type="text/javascript"> function createDatabase(indexDbName) { //調(diào)用 open 方法并傳遞數(shù)據(jù)庫名稱。如果不存在具有指定名稱的數(shù)據(jù)庫,則會創(chuàng)建該數(shù)據(jù)庫 var openRequest = indexedDB.open(indexDbName); var db; openRequest.onerror = function(e) {//當(dāng)創(chuàng)建數(shù)據(jù)庫失敗時候的回調(diào) console.log("Database error: " + e.target.errorCode); }; openRequest.onsuccess = function(event) { console.log("Database created"); db = openRequest.result;//創(chuàng)建數(shù)據(jù)庫成功時候,將結(jié)果給db,此時db就是當(dāng)前數(shù)據(jù)庫 //alert("this is :"+db); }; openRequest.onupgradeneeded = function (evt) {//更改數(shù)據(jù)庫,或者存儲對象時候在這里處理 }; } </script></head><body> <a href="javascript:createDatabase('firstdb')">createDatabase</a></body></html>
上面這段代碼可以創(chuàng)建一個數(shù)據(jù)庫到客戶端。
刪除數(shù)據(jù)庫
通過調(diào)用 deleteDatabase 方法,并且傳入需要刪除的數(shù)據(jù)庫名稱來刪除現(xiàn)有數(shù)據(jù)庫。
function deleteDatabase(indexDbName) { var deleteDbRequest = indexedDB.deleteDatabase(indexDbName); deleteDbRequest.onsuccess = function (event) { console.log("detete database success"); }; deleteDbRequest.onerror = function (e) { console.log("Database error: " + e.target.errorCode); }; }
存儲數(shù)據(jù)
objectstore
在indexdb中沒有表的概念,而是使用objectstore來存儲對象的,一個數(shù)據(jù)庫中可以包含多個objectStore,objectStore是一個靈活的數(shù)據(jù)結(jié)構(gòu),可以存放多種類型數(shù)據(jù)。我們可以使用每條記錄中的某個指定字段作為鍵值(keyPath),也可以使用自動生成的遞增數(shù)字作為鍵值(keyGenerator),也可以不指定。選擇鍵的類型不同,objectStore可以存儲的數(shù)據(jù)結(jié)構(gòu)也有差異
事物
在更新數(shù)據(jù)庫內(nèi)容或者插入新的數(shù)據(jù)時候,需要首先開啟到事物,并且需要制定當(dāng)前事物操作了那些objectstore。
事務(wù)具有三種模式
-
只讀:read,不能修改數(shù)據(jù)庫數(shù)據(jù),可以并發(fā)執(zhí)行
-
讀寫:readwrite,可以進(jìn)行讀寫操作
-
版本變更:verionchange
因為對新數(shù)據(jù)的操作都需要在transaction中進(jìn)行,而transaction又要求指定object store,所以我們只能在創(chuàng)建數(shù)據(jù)庫的時候初始化object store以供后面使用。
指定keyid添加數(shù)據(jù)
指定keyid,可以理解為指定一個主鍵
//添加數(shù)據(jù) function insertAnObj(indexDbName) { var userinfos=[{ id:1001, name:"小李", age:24 },{ id:1002, name:"老王", age:30 },{ id:1003, name:"王麻子", age:26 }]; var openRequest = indexedDB.open(indexDbName,1); openRequest.onerror = function(e) {//當(dāng)創(chuàng)建數(shù)據(jù)庫失敗時候的回調(diào) console.log("Database error: " + e.target.errorCode); }; openRequest.onsuccess = function(event) { console.log("Database created"); db = openRequest.result; //創(chuàng)建數(shù)據(jù)庫成功時候,將結(jié)果給db,此時db就是當(dāng)前數(shù)據(jù)庫 //alert("this is :"+db); //打開和userinfo相關(guān)的objectstore的事物 var transaction = db.transaction("userinfo",'readwrite'); var store=transaction.objectStore("userinfo"); for(var i=0;i<userinfos.length;i++){ //alert("add"+userinfos[i]); store.add(userinfos[i]);//將對象添加至userinfo相關(guān)的objectstore中 } }; openRequest.onupgradeneeded = function(event) { var db = event.target.result; //在第一次創(chuàng)建數(shù)據(jù)庫的時候,就創(chuàng)建userinfo相關(guān)的objectstore,以供后面添加數(shù)據(jù)時候使用 if(!db.objectStoreNames.contains('userinfo')){ //keyPath:Javascript對象,對象必須有一屬性作為鍵值 db.createObjectStore('userinfo',{keyPath:"id"}); } } }
使用autoIncrement添加數(shù)據(jù)
指定autoIncrement,可以理解為指定了一個主鍵自動增長。
//指定主鍵自動增長 function insertAutoInc(indexDbName) { var userinfos=[{ id:1001, name:"小李", age:24 },{ id:1002, name:"老王", age:30 },{ id:1003, name:"王麻子", age:26 }]; var openRequest = indexedDB.open(indexDbName,2); openRequest.onerror = function(e) {//當(dāng)創(chuàng)建數(shù)據(jù)庫失敗時候的回調(diào) console.log("Database error: " + e.target.errorCode); }; openRequest.onsuccess = function(event) { console.log("Database created"); db = openRequest.result; //創(chuàng)建數(shù)據(jù)庫成功時候,將結(jié)果給db,此時db就是當(dāng)前數(shù)據(jù)庫 //alert("this is :"+db); //打開和userinfo相關(guān)的objectstore的事物 var transaction = db.transaction("userinfo",'readwrite'); var store=transaction.objectStore("userinfo"); for(var i=0;i<userinfos.length;i++){ //alert("add"+userinfos[i]); store.add(userinfos[i]);//將對象添加至userinfo相關(guān)的objectstore中 } }; openRequest.onupgradeneeded = function(event) { var db = event.target.result; //在第一次創(chuàng)建數(shù)據(jù)庫的時候,就創(chuàng)建userinfo相關(guān)的objectstore,以供后面添加數(shù)據(jù)時候使用 if(!db.objectStoreNames.contains('userinfo')){ //keyPath:Javascript對象,對象必須有一屬性作為鍵值 db.createObjectStore('userinfo',{autoIncrement: true}); } } }
查找數(shù)據(jù)
根據(jù)id查找數(shù)據(jù)
之前我們已經(jīng)添加過了定義key為autoincreament類型方式的數(shù)據(jù),現(xiàn)在就可以根據(jù)id來查找單條數(shù)據(jù)了。
function findDbdata(indexDbName,value) { var openRequest = indexedDB.open(indexDbName); var db; openRequest.onerror = function(e) {//當(dāng)創(chuàng)建數(shù)據(jù)庫失敗時候的回調(diào) console.log("Database error: " + e.target.errorCode); }; openRequest.onsuccess = function(event) { console.log("Database created"); db = openRequest.result; //創(chuàng)建數(shù)據(jù)庫成功時候,將結(jié)果給db,此時db就是當(dāng)前數(shù)據(jù)庫 var transaction = db.transaction("userinfo",'readwrite'); var objectStore = transaction.objectStore("userinfo"); //var cursor = objectStore.openCursor(); var request = objectStore.get(Number(1));//查找i=1的對象,這里使用Number將1轉(zhuǎn)換成數(shù)值類型 request.onsuccess = function(e) { var res = e.target.result; //查找成功時候返回的結(jié)果對象 console.dir(res); if (res) { for (var field in res) { //遍歷每一個對象屬性 console.log(field+":"+res[field]); // alert(res[field]); }; }; } }; openRequest.onupgradeneeded = function (event) {//更改數(shù)據(jù)庫,或者存儲對象時候在這里處理 }; }
查找所有數(shù)據(jù)
function findAllDbdata(indexDbName) { var openRequest = indexedDB.open(indexDbName); var db; openRequest.onsuccess = function(event) { console.log("Database created"); db = openRequest.result; //創(chuàng)建數(shù)據(jù)庫成功時候,將結(jié)果給db,此時db就是當(dāng)前數(shù)據(jù)庫 var transaction = db.transaction("userinfo",'readonly'); var objectStore = transaction.objectStore("userinfo"); var cursor = objectStore.openCursor(); cursor.onsuccess = function(e) { var res = e.target.result; if(res) { console.log("Key", res.key); var request = objectStore.get(Number(res.key));//根據(jù)查找出來的id,再次逐個查找 request.onsuccess = function(e) { var res = e.target.result; //查找成功時候返回的結(jié)果對象 //console.dir(res); if (res) { for (var field in res) { //遍歷每一個對象屬性 console.log(field+":"+res[field]); // alert(res[field]); }; }; } res.continue(); } } }; }
根據(jù)id刪除數(shù)據(jù)
刪除跟新增一樣,需要創(chuàng)建事務(wù),然后調(diào)用刪除接口delete來刪除數(shù)據(jù)
function deleteDataById(indexDbName) { var openRequest = indexedDB.open(indexDbName); var db; openRequest.onsuccess = function(event) { db = openRequest.result; //創(chuàng)建數(shù)據(jù)庫成功時候,將結(jié)果給db,此時db就是當(dāng)前數(shù)據(jù)庫 var transaction = db.transaction("userinfo",'readwrite'); var objectStore = transaction.objectStore("userinfo"); var request = objectStore.delete(Number(2));//根據(jù)查找出來的id,再次逐個查找 request.onsuccess = function(e) { console.log("delete success"); } } }
刪除所有數(shù)據(jù)
通過objectstore.clear()刪除所有的數(shù)據(jù)。
function deleteAllData(indexDbName) { var openRequest = indexedDB.open(indexDbName); var db; openRequest.onsuccess = function(event) { db = openRequest.result; //創(chuàng)建數(shù)據(jù)庫成功時候,將結(jié)果給db,此時db就是當(dāng)前數(shù)據(jù)庫 var transaction = db.transaction("userinfo",'readwrite'); var objectStore = transaction.objectStore("userinfo"); objectStore.clear(); } }
創(chuàng)建索引
我們可以在創(chuàng)建object store的時候指明索引,使用object store的createIndex創(chuàng)建索引,方法有三個參數(shù)
-
索引名稱
-
索引屬性字段名
-
索引屬性值是否唯一
這里我新創(chuàng)建一個數(shù)據(jù)庫,并且設(shè)置基于name和age的索引:
//指定主鍵自動增長 function insertAutoInc(indexDbName) { var userinfos=[{ id:1001, name:"小李", age:24 },{ id:1002, name:"老王", age:30 },{ id:1003, name:"王麻子", age:26 }]; var openRequest = indexedDB.open(indexDbName,2); openRequest.onerror = function(e) {//當(dāng)創(chuàng)建數(shù)據(jù)庫失敗時候的回調(diào) console.log("Database error: " + e.target.errorCode); }; openRequest.onsuccess = function(event) { console.log("Database created"); db = openRequest.result; //創(chuàng)建數(shù)據(jù)庫成功時候,將結(jié)果給db,此時db就是當(dāng)前數(shù)據(jù)庫 //alert("this is :"+db); //打開和userinfo相關(guān)的objectstore的事物 var transaction = db.transaction("userinfo",'readwrite'); var store=transaction.objectStore("userinfo"); for(var i=0;i<userinfos.length;i++){ //alert("add"+userinfos[i]); store.add(userinfos[i]);//將對象添加至userinfo相關(guān)的objectstore中 } }; openRequest.onupgradeneeded = function(event) { var db = event.target.result; //在第一次創(chuàng)建數(shù)據(jù)庫的時候,就創(chuàng)建userinfo相關(guān)的objectstore,以供后面添加數(shù)據(jù)時候使用 if(!db.objectStoreNames.contains('userinfo')){ //keyPath:Javascript對象,對象必須有一屬性作為鍵值 var objectStore = db.createObjectStore('userinfo',{autoIncrement: true}); objectStore.createIndex('nameIndex','name',{unique:true});//這里假定名字不能重復(fù),創(chuàng)建基于name的唯一索引 objectStore.createIndex('ageIndex','age',{unique:false});//創(chuàng)建基于age的索引 } } }
利用索引查詢數(shù)據(jù)
可以利用索引快速獲取數(shù)據(jù),name的索引是唯一的沒問題,但是對于age索引只會取到第一個匹配值,要想得到所有age符合條件的值就需要使用游標(biāo)了
function getDataByIndex(indexDbName) { var openRequest = indexedDB.open(indexDbName); var db; openRequest.onerror = function(e) {//當(dāng)創(chuàng)建數(shù)據(jù)庫失敗時候的回調(diào) console.log("Database error: " + e.target.errorCode); }; openRequest.onsuccess = function(event) { console.log("Database created"); db = openRequest.result; //創(chuàng)建數(shù)據(jù)庫成功時候,將結(jié)果給db,此時db就是當(dāng)前數(shù)據(jù)庫 var transaction = db.transaction("userinfo",'readwrite'); var objectStore = transaction.objectStore("userinfo"); var nameIndex = objectStore.index("nameIndex"); //獲得nameIndex索引 nameIndex.get("小李").onsuccess = function(e) { //根據(jù)name索引獲得數(shù)據(jù)成功的回調(diào) var userinfo = e.target.result; console.log("id:"+userinfo.id+"==name:"+userinfo.name+"==age:"+userinfo.age); } } }
游標(biāo)和索引結(jié)合使用
剛才我們不僅創(chuàng)建了一個name的唯一索引,而且還創(chuàng)建了一個age的索引,如果我們根據(jù)age來獲取數(shù)據(jù),有可能會有多條,由于age不唯一,所以這個時候就需要使用游標(biāo)來遍歷數(shù)據(jù)。這里我先插入兩條age=24的記錄。
function getDataByAgeIndex(indexDbName) { var openRequest = indexedDB.open(indexDbName); var db; openRequest.onerror = function(e) {//當(dāng)創(chuàng)建數(shù)據(jù)庫失敗時候的回調(diào) console.log("Database error: " + e.target.errorCode); }; openRequest.onsuccess = function(event) { console.log("Database created"); db = openRequest.result; //創(chuàng)建數(shù)據(jù)庫成功時候,將結(jié)果給db,此時db就是當(dāng)前數(shù)據(jù)庫 var transaction = db.transaction("userinfo",'readwrite'); var objectStore = transaction.objectStore("userinfo"); var nameIndex = objectStore.index("ageIndex"); //獲得ageIndex索引 var request = nameIndex.openCursor();//openCursor沒有參數(shù)的時候,表示獲得所有數(shù)據(jù) request.onsuccess = function(e) {//openCursor成功的時候回調(diào)該方法 var cursor = e.target.result; if (cursor) {//循環(huán)遍歷cursor var userinfo = cursor.value; //alert(userinfo.name); console.log("id:"+userinfo.id+"==name:"+userinfo.name+"==age:"+userinfo.age); cursor.continue(); }; } } }
同時可以在opencursor的時候傳入key range,來限制范圍。
IDBKeyRange.only(value):只獲取指定數(shù)據(jù)
IDBKeyRange.lowerBound(value,isOpen):獲取最小是value的數(shù)據(jù),第二個參數(shù)用來指示是否排除value值本身,也就是數(shù)學(xué)中的是否是開區(qū)間
IDBKeyRange.upperBound(value,isOpen):和上面類似,用于獲取最大值是value的數(shù)據(jù)
IDBKeyRange.bound(value1,value2,isOpen1,isOpen2):表示在value1和value2之間,是否包含value1和value2
這里為了演示方便,我先刪除之前的數(shù)據(jù)庫,重新插入更多的數(shù)據(jù),現(xiàn)在所有數(shù)據(jù)如下:
IDBKeyRange.only(value)
這里只需要在上面opencursor的時候?qū)⒃撓拗茥l件傳入即可,其他代碼將保持不變,如下:
var request = nameIndex.openCursor(IDBKeyRange.only(Number(24)));
這里只根據(jù)age索引查詢age==24的所有數(shù)據(jù)。
IDBKeyRange.lowerBound(value,isOpen)
在使用IDBKeyRange.lowerBound(28,true)來獲取年齡大于28的并且包含28歲的所有數(shù)據(jù)。
var request = nameIndex.openCursor(IDBKeyRange.lowerBound(Number(28),true));
ok,今天就到這里了,希望大家喜歡。