摘要:對(duì)象應(yīng)該主要用于僅針對(duì)會(huì)話的小段數(shù)據(jù)的存儲(chǔ)。如下代碼限制與其它客戶端數(shù)據(jù)存儲(chǔ)方案類(lèi)似,同樣也有限制。最好一開(kāi)始就調(diào)用方法為數(shù)據(jù)庫(kù)指定一個(gè)版本號(hào)傳入一個(gè)表示版本號(hào)的字符串。目前就瀏覽器,版本號(hào)方法已不再適用,另外,創(chuàng)建
Cookie 限制
由于瀏覽器存在各種限制,最好將整個(gè)cookie長(zhǎng)度限制在4095B以內(nèi)。
構(gòu)成cookie由瀏覽器保存的以下幾塊信息構(gòu)成:
名稱: cookie的名稱必須是經(jīng)過(guò)URL編碼后的字符串。 雖然它是不區(qū)分大小寫(xiě)的, 但是實(shí)際應(yīng)用時(shí)建議把它當(dāng)作區(qū)分大小寫(xiě)來(lái)使用。
值: cookie中字符串值, 也必須是經(jīng)過(guò)URI編碼的字符串。
域: 表示cookie對(duì)于哪個(gè)域有效。
路徑: cookie是針對(duì)域中的哪個(gè)目錄生效。
失效時(shí)間: 表示cookie失效時(shí)間的時(shí)間戳, 它是GMT格式的日期。 將該事件設(shè)置小于當(dāng)前時(shí), 就相當(dāng)于刪除了cookie。
安全標(biāo)識(shí): 指定該標(biāo)識(shí)后, 只有使用SSL請(qǐng)求連接的時(shí)候cookie才會(huì)發(fā)送到服務(wù)器。 secure標(biāo)識(shí)是cookie中唯一一個(gè)非鍵值對(duì)的部分, 它只包含一個(gè)secure單詞。
使用分號(hào)加空格分開(kāi)各個(gè)信息構(gòu)成:
HTTP/1.1 200 OK Content-type: text/html Set-Cookie: CookieName=CookieValue; expires=Mon, 22-Jan-07 07:10:24 GMT; domain=.wrox.com Other-header: other-header-value
或使用安全標(biāo)志:
HTTP/1.1 200 OK Content-type: text/html Set-Cookie: CookieName=CookieValue; expires=Mon, 22-Jan-07 07:10:24 GMT; domain=.wrox.com; path=/; secure //在這里! Other-header: other-header-valueJavaScript中的Cookie
在JavaScript中可以通過(guò)
document.cookie可以讀取當(dāng)前域名下的cookie, 是用分號(hào)隔開(kāi)的鍵值對(duì)構(gòu)成的字符串。 類(lèi)似于name = aa;
age = 15;
注意所有的鍵值對(duì)名稱和值都是經(jīng)過(guò)encodeURIComponent() 編碼的, 使用時(shí)要進(jìn)行解碼。
當(dāng)給document.cookie賦值時(shí), 不會(huì)直接覆蓋現(xiàn)有的cookie, 而是會(huì)追加一個(gè)新的cookie。 例如:
document.cookie = "a=1"; //執(zhí)行后會(huì)看到新增了一個(gè)cookie。
如:
document.cookie = encodeURIComponent("name") + "=" + encodeURIComponent("Oliver"); console.log(document.cookie); //name=Oliver;
如果給cookie賦值則會(huì)增加一個(gè)cookie:
document.cookie = encodeURIComponent("name") + "=" + encodeURIComponent("Oliver"); document.cookie = encodeURIComponent("age") + "=" + encodeURIComponent("18"); console.log(document.cookie); //name=Oliver; age=18
以下函數(shù)是常用的cookie讀寫(xiě)刪除方法:
var CookieUtil = { //根據(jù)key讀取cookie get: function(name) { //注意對(duì)鍵編碼 var cookieName = encodeURIComponent(name) + "=", cookieStart = document.cookie.indexOf(cookieName), cookieValue = null, cookieEnd; //找到cookie鍵 if (cookieStart > -1) { //鍵后面第一個(gè)分號(hào)位置 cookieEnd = document.cookie.indexOf(";", cookieStart); if (cookieEnd == -1) { cookieEnd = document.cookie.length; } //cookie值解碼 cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd)); } return cookieValue; }, //設(shè)置cookie set: function(name, value, expires, path, domain, secure) { var cookieText = encodeURIComponent(name) + "=" + encodeURIComponent(value); //失效時(shí)間,GMT時(shí)間格式 if (expires instanceof Date) { cookieText += "; expires=" + expires.toGMTString(); } if (path) { cookieText += "; path=" + path; } if (domain) { cookieText += "; domain=" + domain; } if (secure) { cookieText += "; secure"; } document.cookie = cookieText; }, //刪除cookie,保持相同的鍵、域、路徑、安全選項(xiàng),然后設(shè)置失效時(shí)間即可 unset: function(name, path, domain, secure) { this.set(name, "", new Date(0), path, domain, secure); } };
可以像下面這樣使用上述方法:
設(shè)置cookie:
CookieUtil.set("name","Oliver"); CookieUtil.set("age","18"); console.log(document.cookie); //name=Oliver; age=18
讀取cookie的值:
console.log(CookieUtil.get("name")); //Oliver
刪除cookie:
CookieUtil.unset("name"); // console.log(document.cookie); //age=18
設(shè)置cookie路徑、域等:
CookieUtil.set("name","Oliver","/","localhost",null,false);
否則使用下面的代碼創(chuàng)建和刪除cookie:
//新cookie document.cookie = encodeURIComponent("name") + "=" + encodeURIComponent("Oliver"); //刪除上面創(chuàng)建的cookie document.cookie = encodeURIComponent("name") + "=" + encodeURIComponent("Oliver") + "; expires=" + new Date(0);
舉例
css:
DOM:
welcome to my site!
關(guān)閉
js:
子Cookie
由于瀏覽器cookie數(shù)量是有限制的,為了減少cookie數(shù)量可以使用子cookie的方式。在一個(gè)cookie值中使用類(lèi)似查詢字符串的格式可以存儲(chǔ)多組鍵值對(duì),這樣就不必每個(gè)鍵值對(duì)都占用一個(gè)cookie了。子cookie值舉例:
name=name1=value1&name2=value2獲取所有子cookie
獲取所有子cookie并將它放在一個(gè)對(duì)象中返回,對(duì)象的屬性名為子cookie名稱,對(duì)象的屬性值為子cookie的值。
getAll: function(name) { var cookieName = encodeURIComponent(name) + "=", cookieStart = document.cookie.indexOf(cookieName), cookieValue = null, cookieEnd, subCookies, i, parts, result = {}; if (cookieStart > -1) { cookieEnd = document.cookie.indexOf(";", cookieStart) if (cookieEnd == -1) { cookieEnd = document.cookie.length; } //取出cookie字符串值 cookieValue = document.cookie.substring(cookieStart + cookieName.length, cookieEnd); if (cookieValue.length > 0) { //用&將cookie值分隔成數(shù)組 subCookies = cookieValue.split("&"); for (i = 0, len = subCookies.length; i < len; i++) { //等號(hào)分隔出鍵值對(duì) parts = subCookies[i].split("="); //將解碼后的兼職對(duì)分別作為屬性名稱和屬性值賦給對(duì)象 result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]); } return result; } } return null; }獲取單個(gè)子cookie
get()獲取單個(gè)子cookie。
get: function(name, subName) { //獲取所有子cookie var subCookies = this.getAll(name); if (subCookies) { //從屬性中獲取單個(gè)子cookie return subCookies[subName]; } else { return null; } }設(shè)置整個(gè)cookie
setAll設(shè)置整個(gè)cookie
setAll: function(name, subcookies, expires, path, domain, secure) { var cookieText = encodeURIComponent(name) + "=", subcookieParts = new Array(), subName; //遍歷子cookie對(duì)象的屬性 for (subName in subcookies) { //要先檢測(cè)屬性名 if (subName.length > 0 && subcookies.hasOwnProperty(subName)) { //屬性名和屬性值編碼后=連接為字符串,并放到數(shù)組中 subcookieParts.push(encodeURIComponent(subName) + "=" + encodeURIComponent(subcookies[subName])); } } if (subcookieParts.length > 0) { //用&連接子cookie串 cookieText += subcookieParts.join("&"); if (expires instanceof Date) { cookieText += "; expires=" + expires.toGMTString(); } if (path) { cookieText += "; path=" + path; } if (domain) { cookieText += "; domain=" + domain; } if (secure) { cookieText += "; secure"; } } else { cookieText += "; expires=" + (new Date(0)).toGMTString(); } //設(shè)置整個(gè)cookie document.cookie = cookieText; }設(shè)置單個(gè)子cookie
set設(shè)置單個(gè)子cookie
set: function(name, subName, value, expires, path, domain, secure) { //獲取當(dāng)前cookie對(duì)象 var subcookies = this.getAll(name) || {}; //單個(gè)cookie對(duì)應(yīng)的屬性替換 subcookies[subName] = value; //重新設(shè)置cookie this.setAll(name, subcookies, expires, path, domain, secure); }刪除cookie
刪除整個(gè)cookie, 將失效時(shí)間設(shè)置為過(guò)期日期即可。
unsetAll: function(name, path, domain, secure) { this.setAll(name, null, new Date(0), path, domain, secure); }刪除單個(gè)子cookie
刪除單個(gè)子cookie,需要先獲取所有子cookie對(duì)象,然后刪除子cookie對(duì)應(yīng)的屬性,最后再將子cookie對(duì)象重新設(shè)置回去。
unset: function(name, subName, path, domain, secure) { //獲取當(dāng)前cookie對(duì)象 var subcookies = this.getAll(name); if (subcookies) { //刪除子cookie對(duì)應(yīng)的屬性 delete subcookies[subName]; //重新設(shè)置cookie this.setAll(name, subcookies, null, path, domain, secure); } }以下函數(shù)是常用的子cookie讀寫(xiě)刪除方法:
var SubCookieUtil = { getAll: function(name) { var cookieName = encodeURIComponent(name) + "=", cookieStart = document.cookie.indexOf(cookieName), cookieValue = null, cookieEnd, subCookies, i, parts, result = {}; if (cookieStart > -1) { cookieEnd = document.cookie.indexOf(";", cookieStart) if (cookieEnd == -1) { cookieEnd = document.cookie.length; } //取出cookie字符串值 cookieValue = document.cookie.substring(cookieStart + cookieName.length, cookieEnd); if (cookieValue.length > 0) { //用&將cookie值分隔成數(shù)組 subCookies = cookieValue.split("&"); for (i = 0, len = subCookies.length; i < len; i++) { //等號(hào)分隔出鍵值對(duì) parts = subCookies[i].split("="); //將解碼后的兼職對(duì)分別作為屬性名稱和屬性值賦給對(duì)象 result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]); } return result; } } return null; }, get: function(name, subName) { //獲取所有子cookie var subCookies = this.getAll(name); if (subCookies) { //從屬性中獲取單個(gè)子cookie return subCookies[subName]; } else { return null; } }, setAll: function(name, subcookies, expires, path, domain, secure) { var cookieText = encodeURIComponent(name) + "=", subcookieParts = new Array(), subName; //遍歷子cookie對(duì)象的屬性 for (subName in subcookies) { //要先檢測(cè)屬性名 if (subName.length > 0 && subcookies.hasOwnProperty(subName)) { //屬性名和屬性值編碼后=連接為字符串,并放到數(shù)組中 subcookieParts.push(encodeURIComponent(subName) + "=" + encodeURIComponent(subcookies[subName])); } } if (subcookieParts.length > 0) { //用&連接子cookie串 cookieText += subcookieParts.join("&"); if (expires instanceof Date) { cookieText += "; expires=" + expires.toGMTString(); } if (path) { cookieText += "; path=" + path; } if (domain) { cookieText += "; domain=" + domain; } if (secure) { cookieText += "; secure"; } } else { cookieText += "; expires=" + (new Date(0)).toGMTString(); } //設(shè)置整個(gè)cookie document.cookie = cookieText; }, set: function(name, subName, value, expires, path, domain, secure) { //獲取當(dāng)前cookie對(duì)象 var subcookies = this.getAll(name) || {}; //單個(gè)cookie對(duì)應(yīng)的屬性替換 subcookies[subName] = value; //重新設(shè)置cookie this.setAll(name, subcookies, expires, path, domain, secure); }, unsetAll: function(name, path, domain, secure) { this.setAll(name, null, new Date(0), path, domain, secure); }, unset: function(name, subName, path, domain, secure) { //獲取當(dāng)前cookie對(duì)象 var subcookies = this.getAll(name); if (subcookies) { //刪除子cookie對(duì)應(yīng)的屬性 delete subcookies[subName]; //重新設(shè)置cookie this.setAll(name, subcookies, null, path, domain, secure); } } };
舉例:
獲取cookie:
//若cookie為document.cookie=data=name=Oliver&book=jsbook; document.cookie = "data" + "=" + "name" + "=" + "Oliver" + "&" + "book" + "=" + "jsbook"; //取得全部子cookie var data = SubCookieUtil.getAll("data"); console.log(data.name); //Oliver console.log(data.book); //jsbook //獲取單個(gè)子cookie data = SubCookieUtil.get("data", "name"); console.log(data); //Oliver console.log(document.cookie); //data=name=Oliver&book=jsbook
設(shè)置cookie:
//若cookie為document.cookie=data=name=Oliver&book=jsbook; document.cookie = "data" + "=" + "name" + "=" + "Oliver" + "&" + "book" + "=" + "jsbook"; //設(shè)置兩個(gè)cookie SubCookieUtil.set("data", "name", "Nicholas"); SubCookieUtil.set("data", "book", "HTMLreference") console.log(document.cookie); //data=name=Nicholas&book=HTMLreference //設(shè)置全部子cookie SubCookieUtil.setAll("data", { name: "Troy", book: "JSON"}); console.log(document.cookie); //data=name=Troy&book=JSON //修改部分子cookie SubCookieUtil.set("data", "name", "Oli"); console.log(document.cookie); //data=name=Oli&book=JSON
刪除cookie:
//若cookie為document.cookie=data=name=Oliver&book=jsbook; document.cookie = "data" + "=" + "name" + "=" + "Oliver" + "&" + "book" + "=" + "jsbook"; //刪除部分子cookie SubCookieUtil.unset("data", "name"); console.log(document.cookie); //data=book=jsbook //刪除全部cookie SubCookieUtil.unsetAll("data"); console.log(document.cookie); //[This site has nos.]
舉例:
多個(gè)提醒banner的“不再提醒功能”存在同一個(gè)cookie中
css部分:
{
margin: 0; padding: 0;
}
div#message {
border: 1px solid #ccc; background-color: #33CCFF; margin: 0;
}
p.content {
color: white; font-size: 2em; margin: 0.3em; font-family: monospace; display: block;
}
a.notShow {
width: 2em; display: block; float: right;
}
dom部分:
js部分:
//獲取元素 var notShowBtn = document.getElementsByClassName("notShow"); //點(diǎn)擊關(guān)閉按鈕新建cookie并關(guān)閉banner var notShowBtnList = []; var hiddenElementCount = 0; for (var i = 0, len = notShowBtn.length; i < len; i++) { notShowBtnList.push(i); }; notShowBtnList.forEach(function(element, index) { notShowBtn[element].onclick = function() { event.preventDefault(); var value = "content" + element; SubCookieUtil.set("hideMessage", value, "hide"); notShowBtn[element].parentNode.style.display = "none"; }; }); //檢查cookie當(dāng)存在則關(guān)閉banner window.onload = function() { notShowBtnList.forEach(function(element, index) { var value = "content" + element; if (SubCookieUtil.get("hideMessage", value)) { notShowBtn[element].parentNode.style.display = "none"; } }); };IE用戶數(shù)據(jù)
用以下代碼:
然后利用setAttribute()方法保存數(shù)據(jù)
再調(diào)用save()方法保存到指定的數(shù)據(jù)空間
下一次頁(yè)面載入后就可以使用load()方法讀取數(shù)據(jù)
Web儲(chǔ)存機(jī)制最初的Web Storage規(guī)范包含了兩種對(duì)象的定義:sessionStorage和globalStorage,這兩種都是在windows對(duì)象屬性中存在的。
Storage類(lèi)型該類(lèi)型提供最大的存儲(chǔ)空間來(lái)存儲(chǔ)名值對(duì),有一下方法:
clear()刪除所有值;
key(index)獲得index處的名字;
getItem(name)根據(jù)指定的name獲取對(duì)應(yīng)的值;
removeItem(name)刪除name處的名值對(duì);
setItem(name, value)為指定的name設(shè)置一個(gè)對(duì)應(yīng)的值;
其中后三中可以直接調(diào)用也可以通過(guò)Storage對(duì)象間接調(diào)用。
還可以使用length屬性來(lái)判斷有多少名值對(duì)兒存放在Storage對(duì)象中,但無(wú)法判斷對(duì)象中所有數(shù)據(jù)的大小,不過(guò)IE8提供了一個(gè)remainingSpace屬性,用于獲取還可以使用的存儲(chǔ)空間的字節(jié)數(shù)。
sessionStorage對(duì)象sessionStorage對(duì)象存儲(chǔ)特定于某個(gè)會(huì)話的數(shù)據(jù),也就是該數(shù)據(jù)只保持到該瀏覽器關(guān)閉。存儲(chǔ)在sessionStorage中的數(shù)據(jù)可以跨越頁(yè)面刷新而存在,同時(shí)如果瀏覽器支持,瀏覽器崩潰并重啟之后依然可用(Firefox和WebKit都支持,IE則不行)。存儲(chǔ)在sessionStorage中的數(shù)據(jù)只能由最初給定對(duì)象存儲(chǔ)數(shù)據(jù)的頁(yè)面訪問(wèn)到,所以對(duì)頁(yè)面應(yīng)用有限制。
存儲(chǔ)數(shù)據(jù)可以使用setItem()或者直接設(shè)置新的屬性來(lái)存儲(chǔ)數(shù)據(jù)。下面是這兩種方法的例子。
sessionStorage.setItem("name", "Oliver"); //使用方法存儲(chǔ)數(shù)據(jù) sessionStorage.book = "JSON.com"; //使用屬性存儲(chǔ)數(shù)據(jù)
Firefox和Webkit實(shí)現(xiàn)了同步寫(xiě)入,所以添加到存儲(chǔ)空間中的數(shù)據(jù)是立刻被提交的。而IE的實(shí)現(xiàn)則是異步寫(xiě)入數(shù)據(jù),所以在設(shè)置數(shù)據(jù)和將數(shù)據(jù)實(shí)際寫(xiě)入磁盤(pán)之間可能有一些延遲。
在IE8中可以強(qiáng)制把數(shù)據(jù)寫(xiě)入磁盤(pán):在設(shè)置新數(shù)據(jù)之前使用
begin()方法
并且所有設(shè)置完成之后調(diào)用
commit()方法
看以下例子:
sessionStorage.begin(); sessionStorage.name = "oli"; sessionStorage.commit();讀取數(shù)據(jù)
getItem()
可以使用getItem()或者通過(guò)直接訪問(wèn)屬性名來(lái)獲取數(shù)據(jù)。
sessionStorage.name = "oli"; sessionStorage.age = 18; var val = sessionStorage.name; var val_1 = sessionStorage.age; console.log(val); //oli console.log(val_1); //18迭代數(shù)據(jù)
key()方法
通過(guò)結(jié)合length屬性和key()方法來(lái)迭代sessionStorage中的值
for (var i = 0, len = sessionStorage.length; i < len; i++) { var key = sessionStorage.key(i); var val = sessionStorage.getItem(key); console.log(key + "=" + val); };
for-in方法
還可以使用for-in循環(huán)來(lái)迭代sessionStorage中的值:
for (key in sessionStorage) { var value = sessionStorage.getItem(key); console.log(key + "=" + value); }刪除數(shù)據(jù)
removeItem()方法
要從sessionStorage中刪除數(shù)據(jù),可以使用delete操作符刪除對(duì)象屬性,也可調(diào)用removeItem()方法。
sessionStorage.name = "oli"; sessionStorage.age = 18; sessionStorage.removeItem("name"); delete sessionStorage.age;
sessionStorage對(duì)象應(yīng)該主要用于僅針對(duì)會(huì)話的小段數(shù)據(jù)的存儲(chǔ)。
globalStorage對(duì)象(被localStorage對(duì)象取代)Firefox 2中實(shí)現(xiàn)了globalStorage對(duì)象。作為最初的Web Storage規(guī)范的一部分,這個(gè)對(duì)象的目的是跨越會(huì)話存儲(chǔ)數(shù)據(jù),但有特定的訪問(wèn)限制。要使用globalStorage,首先要指定哪些域可以訪問(wèn)該數(shù)據(jù)??梢酝ㄟ^(guò)方括號(hào)標(biāo)記使用屬性來(lái)實(shí)現(xiàn),如以下例子所示。
globalStorage["test.com"].name = "Oliver"; var name = globalStorage["test.com"].name;
其中,globalStorage不是Storage的實(shí)例,globalStorage["test.com"]才是
某些瀏覽器允許更加寬泛的訪問(wèn)限制,比如只根據(jù)頂級(jí)域名進(jìn)行限制或者允許全局訪問(wèn),如下面例子所示:
//存儲(chǔ)數(shù)據(jù),任何人都可以訪問(wèn)——不要這樣做! globalStorage[""].name = "Nicholas"; //存儲(chǔ)數(shù)據(jù),可以讓任何以.net結(jié)尾域名訪問(wèn)——不要這樣做! globalStorage["net"].name = "Nicholas";
要避免使用這種可寬泛訪問(wèn)的數(shù)據(jù)存儲(chǔ)
對(duì)globalStorage空間的訪問(wèn),是一句發(fā)起請(qǐng)求的頁(yè)面的域名、協(xié)議和端口來(lái)限制的。例如,如果使用HTTPS協(xié)議在w3cmm.com中存儲(chǔ)了數(shù)據(jù),那么通過(guò)HTTP訪問(wèn)的w3cmm.com的頁(yè)面就不能訪問(wèn)該數(shù)據(jù)。
globalStorage的每個(gè)屬性都是Storage的實(shí)例。因此,可以像如下代碼中這樣使用。
globalStorage["www.test.com"].name = "Nicholas"; globalStorage["www.test.com"].book = "Professional JavaScript"; globalStorage["www.test.com"].removeItem("name"); var book = globalStorage["www.test.com"].getItem("book");
如果你事先不能確定域名,那么使用location.host作為屬性名比較安全。例如:
globalStorage[location.host].name = "Nicholas"; var book = globalStorage[location.host].getItem("book");localStorage對(duì)象
localStorage對(duì)象在修訂過(guò)的HTML5規(guī)范中作為持久保存在客戶端數(shù)據(jù)的方案取代了globalStorage。要訪問(wèn)同一個(gè)localStorage對(duì)象,頁(yè)面必須來(lái)自同一個(gè)域名(子域名無(wú)效),使用同一種協(xié)議,在同一個(gè)端口上。這相當(dāng)于globalStorage[location.host]。
由于localStorage是Storage的實(shí)例,所以可以像使用sessionStorage一樣來(lái)使用它。下面是一些例子。
localStorage.setItem("name", "Oliver"); localStorage.book = "JSON"; var book = localStorage.book; var name = localStorage.getItem("name"); localStorage.removeItem("name"); delete localStorage.book; localStorage.clear();storage事件
對(duì)Storage對(duì)象進(jìn)行任何修改,都會(huì)在文檔上觸發(fā)storage事件。當(dāng)通過(guò)屬性或setItem()方法保存數(shù)據(jù),使用delete操作符或removeItem()刪除數(shù)據(jù),或著調(diào)用clear()方法時(shí),都會(huì)發(fā)生該事件。這個(gè)事件的event對(duì)象有以下屬性。
domain:發(fā)生變化的存儲(chǔ)空間的域名。
key:設(shè)置或著刪除的鍵名。
newValue:如果是設(shè)置值,則是新值;如果是刪除鍵,則是null。
oldValue:鍵被更改之前的值。
如下代碼:
var EventUtil = { addHandler: function(element, type, handler) { if (element.addEventListener) { element.addEventListener(type, handler, false); } else if (element.attachEvent) { element.attachEvent("on" + type, handler); } else { element["on" + type] = handler; } } }; EventUtil.addHandler(document, "storage", function(event) { alert("Storage changed for " + event.domain); });限制
與其它客戶端數(shù)據(jù)存儲(chǔ)方案類(lèi)似,Web Storage同樣也有限制。這些限制因?yàn)g覽器而異。一般來(lái)說(shuō),對(duì)存儲(chǔ)空間大小的限制都是以每個(gè)來(lái)源(協(xié)議、域和端口)為單位的。
對(duì)于localStorage而言,大多數(shù)桌面瀏覽器會(huì)設(shè)置每個(gè)來(lái)源5MB的限制。Chrome和Safari對(duì)每個(gè)來(lái)源的限制是2.5MB。而ios版Safari和Android版Webkit的限制也是2.5MB。
對(duì)sessionStorage的限制也是因?yàn)g覽器而異。有的瀏覽器對(duì)sessionStorage的大小沒(méi)有限制,但Chrome、Safari、ios版Safari和Android版Webkit都有限制,也都是2.5MB。IE8+和Opera對(duì)sessionStorage的限制是5MB。
IndexedDB推薦一篇文章使用 IndexedDB,來(lái)自MDN,鏈接地址:https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API/Using_IndexedDB
Indexed Database API 簡(jiǎn)稱為IndexedDB,是在瀏覽器中保存結(jié)構(gòu)化數(shù)據(jù)的一種數(shù)據(jù)庫(kù)。
設(shè)計(jì)思想是建立一套API,方便保存和讀取JavaScript對(duì)象,同時(shí)還支持查詢和搜索。
該操作完全是異步進(jìn)行的。
差不多每一次IndexedDB操作,都需要注冊(cè)onerror或onsuccess事件處理程序,以確保適當(dāng)?shù)靥幚斫Y(jié)果。
在使用時(shí)需要加上瀏覽器提供商前綴:
var indexDB = window.indexedDB || window.msIndexedDB || window.mozIndexedDB || window.webkitIndexedDB;打開(kāi)數(shù)據(jù)庫(kù)
indexDB.open()
IndexedDB就是一個(gè)數(shù)據(jù)庫(kù),IndexedDB最大的特色是使用對(duì)象保存數(shù)據(jù),而不是使用表來(lái)保存數(shù)據(jù)。
使用IndexedDB前首先要打開(kāi)它,即把要打開(kāi)的數(shù)據(jù)庫(kù)名傳給indexDB.open()。如果傳入的數(shù)據(jù)庫(kù)已經(jīng)存在,就會(huì)發(fā)送一個(gè)打開(kāi)它的請(qǐng)求;如果傳入的數(shù)據(jù)庫(kù)還不存在,就會(huì)發(fā)送一個(gè)創(chuàng)建并打開(kāi)它的請(qǐng)求;
總之,調(diào)用indexedDB.open()會(huì)返回一個(gè)IDBRequest對(duì)象,在這個(gè)對(duì)象上可以添加onerror和onsuccess事件處理程序。
var request, database; request = indexedDB.open("Base"); request.onerror = function () { console.log(event.target.errorCode); }; request.onsuccess = function () { database = event.target.result; console.log(event.target.result); //IDBDatabase {} 指向數(shù)據(jù)庫(kù)實(shí)例對(duì)象 console.log(event.target); //IDBOpenDBRequest {} 指向request對(duì)象 };
ABORT_ERR錯(cuò)誤碼8 : A request was aborted,
example, through a call to IDBTransaction.abort.
CONSTRAINT_ERR錯(cuò)誤碼4 : A mutation operation in the transaction failed because a constraint was not satisfied.For example, an object, such as an object store or index, already exists and a request attempted to create a new one.
DATA_ERR錯(cuò)誤碼5 : Data provided to an operation does not meet requirements.
NON_TRANSIENT_ERR錯(cuò)誤碼2 : An operation was not allowed on an object.Unless the cause of the error is corrected, retrying the same operation would result in failure.
NOT_ALLOWED_ERR錯(cuò)誤碼6 :
An operation was called on an object where it is not allowed or at a time when it is not allowed.It also occurs
if a request is made on a source object that has been deleted or removed.
More specific variants of this error includes: TRANSACTION_INACTIVE_ERR and READ_ONLY_ERR.
NOT_FOUND_ERR錯(cuò)誤碼3 : The operation failed because the requested database object could not be found;
example, an object store did not exist but was being opened.
QUOTA_ERR錯(cuò)誤碼11 : Either there "s not enough remaining storage space or the storage quota was reached and the user declined to give more space to the database.
READ_ONLY_ERR錯(cuò)誤碼9 : A mutation operation was attempted in a READ_ONLY transaction.
TIMEOUT_ERR錯(cuò)誤碼10 : A lock
the transaction could not be obtained in a reasonable time.
TRANSACTION_INACTIVE_ERR錯(cuò)誤碼7 : A request was made against a transaction that is either not currently active or is already finished.
UNKNOWN_ERR錯(cuò)誤碼1 : The operation failed
reasons unrelated to the database itself, and it is not covered by any other error code--
for example, a failure due to disk IO errors.
VER_ERR錯(cuò)誤碼12 : A request to open a database with a version lower than the one it already has.This can only happen with IDBOpenDBRequest.
數(shù)據(jù)庫(kù)版本號(hào)indexedDB.setVersion()設(shè)置版本號(hào)
indexedDB.version獲取版本號(hào)
默認(rèn)情況下,IndexedDB數(shù)據(jù)庫(kù)是沒(méi)有版本號(hào)的。最好一開(kāi)始就調(diào)用setVersion()方法為數(shù)據(jù)庫(kù)指定一個(gè)版本號(hào)(傳入一個(gè)表示版本號(hào)的字符串)。
目前就chrome瀏覽器,版本號(hào)方法已不再適用,另外,創(chuàng)建database后chrome瀏覽器自動(dòng)設(shè)置版本號(hào)為"1":
var request, database; request = indexedDB.open("Base"); request.onerror = function () { console.log(event.target.errorCode); }; request.onsuccess = function () { database = event.target.result; console.log(database.setVersion); //undefined console.log(database.version); //1 };
要更新數(shù)據(jù)庫(kù)的 schema,也就是創(chuàng)建或者刪除對(duì)象存儲(chǔ)空間,需要實(shí)現(xiàn) onupgradeneeded 處理程序,這個(gè)處理程序?qū)?huì)作為一個(gè)允許你處理對(duì)象存儲(chǔ)空間的 versionchange 事務(wù)的一部分被調(diào)用。
request.onupgradeneeded
如:
// 該事件僅在較新的瀏覽器中被實(shí)現(xiàn) request.onupgradeneeded = function(event) { // 更新對(duì)象存儲(chǔ)空間和索引 .... };
如需設(shè)置數(shù)據(jù)庫(kù)版本號(hào),用下面方法:(舊)
var request, database; request = indexedDB.open("Base"); request.onerror = function() { console.log(event.target.errorCode); }; request.onsuccess = function() { database = event.target.result; if (database.version != "1.0") { request = database.setVersion("1.0"); request.onerror = function() { console.log(event.target.errorCode); }; request.onsuccess = function() { console.log("database name: " + database.name + "; version: " + database.version); }; } else { console.log("database name: " + database.name + "; version: " + database.version); //database name: Base; version: 1 }; };創(chuàng)建對(duì)象存儲(chǔ)空間
建立完數(shù)據(jù)庫(kù)連接以后,就要?jiǎng)?chuàng)建對(duì)象存儲(chǔ)空間。
鍵的提供可以有幾種不同的方法,這取決于對(duì)象存儲(chǔ)空間是使用 key path 還是 key generator。
若要保存用戶記錄由用戶名、密碼組成,那么保存一條記錄的對(duì)象應(yīng)該如下所示:
var userData = [{ username: "007", firstName: "James", lastName: "Bond", password: "foo" }, { username: "005", firstName: "Oliver", lastName: "Young", password: "boo" }];
其中username為鍵(keyPath),這個(gè)應(yīng)該是全局唯一的(代表一個(gè)user)。
下面是為了保存用戶記錄而創(chuàng)建對(duì)象存儲(chǔ)空間的示例:
var request = indexedDB.open("Base", 2); //注意填寫(xiě)版本號(hào) request.onerror = function() { console.log(event.target.errorCode); }; request.onupgradeneeded = function() { var database = event.target.result; var store = database.createObjectStore("users", { keyPath: "username" }); //根據(jù)username創(chuàng)建一個(gè)名為users的對(duì)象集合(表) };
獲得了對(duì)象存儲(chǔ)空間的引用之后,就可以使用
向?qū)ο蟠鎯?chǔ)空間添加數(shù)據(jù)add()或put()方法向其中添加數(shù)據(jù)
這兩個(gè)方法都接收一個(gè)參數(shù),即要保存的對(duì)象,然后這個(gè)對(duì)象就會(huì)被保存到存儲(chǔ)空間中。
這兩個(gè)方法的區(qū)別在于,如果空間中已經(jīng)包含了鍵值相同的對(duì)象:add()會(huì)返回錯(cuò)誤;put()則會(huì)重寫(xiě)原有對(duì)象;
可以使用下面的代碼初始化(add()方法)存儲(chǔ)空間:
request.onupgradeneeded = function() { var database = event.target.result; var store = database.createObjectStore("users", { keyPath: "username" }); for (var i in userData) { store.add(userData[i]); } };
for-in循環(huán)可用下面代碼代替:
//users中保存著一批的用戶對(duì)象 var i = 0, request, requests[], len = users.length; while (i < len) { request = store.add(users[i++]); request.onerror = function() { // 錯(cuò)誤處理 }; request.onsuccess = function() { // 成功 }; requests.push(request); }
以下為完整的創(chuàng)建數(shù)據(jù)庫(kù)和存儲(chǔ)空間以及初始化數(shù)據(jù)的代碼例子:
// //數(shù)據(jù)在這里userData // var userData = [{ username: "007", //username唯一 firstName: "James", lastName: "Bond", password: "foo" }, { username: "005", firstName: "Oliver", lastName: "Young", password: "boo" }]; // //創(chuàng)建數(shù)據(jù)庫(kù)Alldata // var request = indexedDB.open("allData"); request.onerror = function() { console.log(event.target.errorCode); }; request.onsuccess = function() { var database = event.target.result; console.log("數(shù)據(jù)庫(kù)已經(jīng)創(chuàng)建:" + database.name + "; 版本號(hào):" + database.version); }; // //創(chuàng)建存儲(chǔ)空間(表)users,并初始化數(shù)據(jù) // var request = indexedDB.open("allData", 2); request.onupgradeneeded = function() { var database = event.target.result; //創(chuàng)建存儲(chǔ)空間 var store = database.createObjectStore("users", { keyPath: "username" }); //添加數(shù)據(jù) for (var i in userData) { store.add(userData[i]); } };
另外,下面是數(shù)據(jù)庫(kù)結(jié)構(gòu):
indexedDB |-allData數(shù)據(jù)庫(kù) |-users存儲(chǔ)空間(表) |-(userData數(shù)據(jù))事務(wù)(讀取、修改數(shù)據(jù))
在數(shù)據(jù)庫(kù)對(duì)象上調(diào)用transaction()方法就可以創(chuàng)建事務(wù)。任何時(shí)候,想要讀取或修改數(shù)據(jù),都要通過(guò)事務(wù)來(lái)組織所有的操作。
下面的代碼保證只加載users存儲(chǔ)空間中的數(shù)據(jù),以便通過(guò)事務(wù)進(jìn)行訪問(wèn):
var transaction = database.transaction("users");
要訪問(wèn)多個(gè)對(duì)象存儲(chǔ)空間,可以傳入字符串?dāng)?shù)組:
var transaction = db.transaction(["users", "anotherStore"]);
上面的兩個(gè)事務(wù)都是以只讀的方式訪問(wèn)數(shù)據(jù)。要修改訪問(wèn)方式,必須在創(chuàng)建事務(wù)時(shí)傳入第二個(gè)參數(shù)。
訪問(wèn)模式默認(rèn)都是以只讀的方式訪問(wèn)數(shù)據(jù),要修改訪問(wèn)方式,必須傳入第二個(gè)參數(shù),這個(gè)參數(shù)表示訪問(wèn)模式:
READ_ONLY(0)表示只讀;
READ_WRITE(1)表示讀寫(xiě);
VERSION_CHANGE(2)表示改變
注意: 舊版實(shí)驗(yàn)性的實(shí)現(xiàn)使用不建議使用的常量 IDBTransaction.READ_WRITE 而不是 "readwrite"。
所以現(xiàn)在一般表示讀寫(xiě)應(yīng)該傳入字符串"readwrite"
其中,上面三個(gè)訪問(wèn)模式已經(jīng)被改為:
"readonly"只讀;
"readwrite"讀寫(xiě);
如下:
var request = database.transaction("users", "readonly");訪問(wèn)存儲(chǔ)空間
objectStore()方法,并傳入存儲(chǔ)空間的名稱,就可以訪問(wèn)特定的存儲(chǔ)空間了。
就可以:
使用add()和put()方法添加數(shù)據(jù);
使用get()可以取得值;
使用delete()可以刪除對(duì)象;
使用clear()可以刪除所有對(duì)象;
get()和delete()方法都接收一個(gè)對(duì)象鍵作為參數(shù)。所有的這5個(gè)方法都會(huì)返回一個(gè)新的請(qǐng)求對(duì)象。例如:
var request = database.transaction("users", "readonly").objectStore("users").get("007"); request.onsuccess = function () { var result = event.target.result; //"James" console.log(result.firstName); }; var request = database.transaction("users", "readwrite").objectStore("users").delete("005");
事務(wù)本身也有事件處理程序:onerror和oncomplete。
這兩個(gè)事件可以提供事務(wù)級(jí)的狀態(tài)信息。
注意:通過(guò)oncomplete事件的事件對(duì)象訪問(wèn)不到get()請(qǐng)求返回的任何數(shù)據(jù),必須在onsuccess事件處理程序中才能訪問(wèn)到。
以下為實(shí)例:
var userData = [{ username: "007", //username唯一 firstName: "James", lastName: "Bond", password: "foo" }, { username: "005", firstName: "Oliver", lastName: "Young", password: "boo" }]; //創(chuàng)建數(shù)據(jù)庫(kù)Alldata var request = indexedDB.open("allData"); request.onerror = function() { console.log(event.target.errorCode); }; request.onsuccess = function() { var database = event.target.result; console.log("數(shù)據(jù)庫(kù)已經(jīng)創(chuàng)建:" + database.name + "; 版本號(hào):" + database.version); }; //創(chuàng)建存儲(chǔ)空間(表)users并初始化數(shù)據(jù) var request = indexedDB.open("allData", 2); var database; request.onupgradeneeded = function() { database = event.target.result; //創(chuàng)建存儲(chǔ)空間 var store = database.createObjectStore("users", { keyPath: "username" }); //添加數(shù)據(jù) for (var i in userData) { store.add(userData[i]); } }; var newPerson = { username: "001", firstName: "Troy", lastName: "Ruby", password: "hello" }; //事務(wù) var request = indexedDB.open("allData", 2); request.onsuccess = function () { var database = event.target.result; // var request = database.transaction("users").objectStore("users").add(newPerson); //報(bào)錯(cuò),因?yàn)橹蛔x,需要設(shè)置為"readwrite" var request = database.transaction("users", "readwrite").objectStore("users").add(newPerson); var request = database.transaction("users", "readonly").objectStore("users").get("007"); request.onsuccess = function () { var result = event.target.result; //"James" console.log(result.firstName); }; var request = database.transaction("users", "readwrite").objectStore("users").delete("005"); };使用游標(biāo)查詢
游標(biāo)就是指向結(jié)果集的一個(gè)指針,在對(duì)象存儲(chǔ)空間上調(diào)用;在需要檢索多個(gè)對(duì)象的情況下,需要在事務(wù)內(nèi)部創(chuàng)建游標(biāo)。注意,必須在事務(wù)內(nèi)部創(chuàng)建!
openCursor()方法可以創(chuàng)建游標(biāo)。
openCursor()方法返回的也是一個(gè)請(qǐng)求對(duì)象,也需要為該對(duì)象指定onsuccess和onerror事件處理函數(shù)
var transaction = database.transaction("users", "readonly").objectStore("users").openCursor();
或者:
var store = db.transaction("users").objectStore("users"), request = store.openCursor(); request.onsuccess = function(event) { // 處理成功 }; request.onerror = function(event) { // 處理失敗 };IDBCursor
在前面的onsuccess事件處理程序執(zhí)行時(shí),可以通過(guò)event.target.result取得存儲(chǔ)空間中的下一個(gè)對(duì)象。
IDBCursor實(shí)例具有以下幾個(gè)屬性:
key: 對(duì)象的鍵;
value:實(shí)際的對(duì)象;
direction:數(shù)值,表示游標(biāo)走動(dòng)的方向。
默認(rèn)是IDBCursor.NEXT(0), 表示下一項(xiàng)。
IDBCursor.NEXT_TO_DUPLICATE(1), 表示下一個(gè)不重復(fù)的項(xiàng);
IDBCursor.PREV(2)表示前一項(xiàng);
IDBCursor.PREV_NO_DUPLICATE表示前一個(gè)不重復(fù)的項(xiàng)。
primaryKey:游標(biāo)使用的鍵,有可能是對(duì)象鍵,也有可能是索引鍵(后面會(huì)討論索引)
檢索結(jié)果信息要檢索某個(gè)信息的結(jié)果,如下代碼:
var transaction = database.transaction("users", "readonly").objectStore("users").openCursor(); transaction.onsuccess = function() { var cursor = event.target.result; if (cursor) { console.log(cursor); //IDBCursorWithValue {}direction: "next"key: "005"primaryKey: "005"source: IDBObjectStorevalue: Object__proto__: IDBCursorWithValue console.log(cursor.value); //Object {username: "005", firstName: "Oliver", lastName: "Young", password: "boo"} console.log(cursor.key); //005 console.log("Key: " + cursor.key + "; Value: " + JSON.stringify(cursor.value)); //Key: 005; Value: {"username":"005","firstName":"Oliver","lastName":"Young","password":"boo"} } };
注意:返回的cursor.value是一個(gè)對(duì)象,必要時(shí)需要用到JSON.stringify方法
使用游標(biāo)更新記錄update()方法更新記錄
調(diào)用update()方法可以使用指定的對(duì)象更新當(dāng)前游標(biāo)的value:
var transaction = database.transaction("users", "readwrite").objectStore("users").openCursor(); transaction.onsuccess = function() { var cursor = event.target.result; if (cursor) { if (cursor.key == "005") { console.log(cursor.value.firstName); //游標(biāo)在第一個(gè)位置”005“所以他的firstName就是"Oliver"; 刷新瀏覽器,顯示的結(jié)果則為Oli var value = cursor.value; //更改當(dāng)前游標(biāo)所指的對(duì)象("005")的firstName為"Oli"; value.firstName = "Oli"; var updateRequest = cursor.update(value); //使用update方法請(qǐng)求保存更新 updateRequest.onerror = function () { console.log(event.target.errorCode); }; updateRequest.onsuccess = function () { console.log("success"); //success }; } } }; transaction.onerror = function() { console.log(event.target.errorCode); };使用游標(biāo)刪除記錄
delete()方法刪除記錄
如:
var transaction = database.transaction("users", "readwrite").objectStore("users").openCursor(); transaction.onsuccess = function() { var cursor = event.target.result; if (cursor) { if (cursor.key == "005") { var deleteRequest = cursor.delete(); //請(qǐng)求刪除此項(xiàng) deleteRequest.onerror = function () { // body... }; deleteRequest.onsuccess = function () { // body... }; } } };
注意:如果當(dāng)前的事務(wù)沒(méi)有修改對(duì)象存儲(chǔ)空間的權(quán)限,update()和delete()會(huì)拋出錯(cuò)誤。
移動(dòng)游標(biāo)默認(rèn)情況下每個(gè)游標(biāo)只發(fā)起一次請(qǐng)求;要想發(fā)起另一次請(qǐng)求,必須調(diào)用下面的一個(gè)方法:
continue(key): 移動(dòng)到結(jié)果集的下一項(xiàng)。參數(shù)key是可選的,不指定這個(gè)參數(shù),游標(biāo)移動(dòng)到下一項(xiàng);指定這個(gè)參數(shù)的話,游標(biāo)會(huì)移動(dòng)到指定鍵的位置。
advance(count): 向前移動(dòng)count指定的項(xiàng)數(shù)。
遍歷使用移動(dòng)游標(biāo)的方法,可以用來(lái)遍歷存儲(chǔ)空間中的所有項(xiàng):
var transaction = database.transaction("users", "readwrite").objectStore("users").openCursor(); transaction.onsuccess = function() { var cursor = event.target.result; if (cursor) { console.log("Key: " + cursor.key + "; Value: " + JSON.stringify(cursor.value)); cursor.continue(); //移動(dòng)下一項(xiàng) } else { console.log("done"); } };
調(diào)用continue()會(huì)觸發(fā)另一次請(qǐng)求,進(jìn)而再次調(diào)用onsuccess處理程序。如果沒(méi)有更多項(xiàng)可以遍歷時(shí),event.target.result的值為null。
鍵范圍 IDBKeyRange鍵范圍由IDBKeyRange的實(shí)例表示。
有四中定義鍵范圍的方式:
only()方法:var onlyrange = IDBKeyRange.only("007"); var transaction = database.transaction("users", "readwrite").objectStore("users").openCursor(onlyrange);
將onlyrange變量傳入openCursor方法中
lowerBound()方法:第二種定義鍵范圍的方法是指定結(jié)果集的下界。下界表示游標(biāo)開(kāi)始的位置。
如果想要忽略鍵為"007"的對(duì)象本身,從它的下一個(gè)對(duì)象開(kāi)始,可以傳入第二個(gè)參數(shù)true:
var lowerBound = IDBKeyRange.lowerBound("003", true); //第二個(gè)參數(shù)為true表示不包括003 var transaction = database.transaction("users", "readwrite").objectStore("users").openCursor(lowerBound);upperBound()方法
第三種定義鍵范圍的方法是指定結(jié)果集的上界,也就是指定游標(biāo)不能超過(guò)哪個(gè)鍵。
如果不想包含鍵為指定值的對(duì)象,同樣傳入第二個(gè)參數(shù)true:
var upperBound = IDBKeyRange.upperBound("005", true); //第二個(gè)參數(shù)為true表示不包括005 var transaction = database.transaction("users", "readwrite").objectStore("users").openCursor(upperBound);bound()方法
使用bound()方法可以同時(shí)指定上下界。
這個(gè)方法可以接收四個(gè)參數(shù):表示下界的鍵,表示上界的鍵,可選的表示是否跳過(guò)下界的布爾值和可選的表示是否跳過(guò)上界的布爾值。
var bound = IDBKeyRange.bound("003", "005", true, false); //第三和第四個(gè)參數(shù)為true和false表示不包括003包括005 var transaction = database.transaction("users", "readwrite").objectStore("users").openCursor(bound);設(shè)定游標(biāo)方向
openCursor()可以接收兩個(gè)參數(shù),一個(gè)是剛才的IDBKeyRange實(shí)例,第二個(gè)是表示方向的數(shù)值常量,也就是前面講到的IDBCursor中的常量。
正常情況下,游標(biāo)都是從存儲(chǔ)空間的第一項(xiàng)開(kāi)始,調(diào)用continue()或advance()前進(jìn)到最后一項(xiàng)。游標(biāo)的默認(rèn)方向值是
IDBCursor.NEXT或IDBCursor.NEXT_NO_DUPLICATE
IDBCursor.next或IDBCursor.nextunique
也可以創(chuàng)建一個(gè)游標(biāo),從最后一個(gè)對(duì)象開(kāi)始,逐個(gè)迭代,直到第一個(gè)對(duì)象,這時(shí)要傳入的常量是:
IDBCursor.PREV或IDBCursor.PREV_NO_DUPLICATE
IDBCursor.prev或IDBCursor.prevunique
索引對(duì)于有些數(shù)據(jù),需要?jiǎng)?chuàng)建多個(gè)鍵,如把用戶ID作為主鍵,以用戶名創(chuàng)建索引
創(chuàng)建索引首先引用對(duì)象存儲(chǔ)空間,然后調(diào)用
createIndex()方法
如下:
request.onupgradeneeded = function() { var database = event.target.result; var store = database.createObjectStore("users", { keyPath: "username" }); for (var i in userData) { store.add(userData[i]); } var index = store.createIndex("firstName", "firstName", { unique: false }); //創(chuàng)建名為firstName的索引,屬性名為firstName,屬性值非唯一 };使用索引
index()方法
如下:
var index = database.transaction("users").objectStore("users").index("firstName"); console.log(index); //IDBIndex對(duì)象索引上創(chuàng)建游標(biāo)
openCursor()方法
如下:
var request = index.openCursor(); request.onsuccess = function () { console.log(event.target.result); //IDBCursorWithValue對(duì)象 };
遍歷:
var request = index.openCursor(); request.onsuccess = function() { var cursor = event.target.result; //IDBCursorWithValue對(duì)象 if (cursor) { console.log(cursor.key + "; " + JSON.stringify(cursor.value)); cursor.continue(); } else { console.log("done"); } // Alice; { // "username": "003", // "firstName": "Alice", // "lastName": "Young", // "password": "boo" // } // (index): 87 James; { // "username": "007", // "firstName": "James", // "lastName": "Bond", // "password": "foo" // } // (index): 87 Oliver; { // "username": "005", // "firstName": "Oliver", // "lastName": "Young", // "password": "boo" // } // (index): 90 done };索引上創(chuàng)建主鍵的游標(biāo)
openKeyCursor()方法
調(diào)用這個(gè)特殊的只返回每條記錄主鍵的游標(biāo),這個(gè)方法在event.result.key中保存索引鍵,在event.result.value中保存的則是主鍵,而不是整個(gè)對(duì)象
索引中取得對(duì)象get()方法
只要傳入相應(yīng)的索引鍵即可:
var store = db.transaction("users").objectStore("users"); var index = store.index("firstName"); var request = index.get("007");根據(jù)索引鍵取得主鍵
getKey()方法
這個(gè)方法中event.result.value等于主鍵的值,而不是整個(gè)對(duì)象:
var store = db.transaction("users").objectStore("users"); var index = store.index("firstName"); var request = index.getKey("007");索引IDBIndex對(duì)象的屬性
name:索引的名字
keyPath:createIndex方法中屬性的路徑
objectStore:索引的對(duì)象存儲(chǔ)空間
unique:表示索引鍵是否唯一
訪問(wèn)所有索引indexNames屬性
如:
var indexNames = store.indexNames; for (var i = 0, len = store.indexNames.length; i < len; i++) { var index = store.index(indexNames[i]); console.log(index.name); //firstName //lastName };刪除索引
deleteIndex()
如:
store.deleteIndex("firstName");并發(fā)問(wèn)題
每次打開(kāi)數(shù)據(jù)庫(kù),都應(yīng)該指定onversionchange事件處理程序:
request.onsuccess = function() { database = event.target.result; database.onversionchange = function () { database.close(); }; };
當(dāng)設(shè)置version時(shí),指定請(qǐng)求的onblocked事件處理程序也很重要:
var request = database.setVersion("2.0"); request.onblocked = function () { alert("輕先關(guān)閉其他標(biāo)簽頁(yè)后再嘗試"); }; request.onsuccess = function () { //處理成功,繼續(xù) };限制
同源
多個(gè)限制5MB大小
Firefox不允許本地訪問(wèn)IndexedDB
完整的例子var userData = [{ username: "007", firstName: "James", lastName: "Bond", password: "foo" }, { username: "005", firstName: "Oliver", lastName: "Young", password: "boo" }, { username: "003", firstName: "Alice", lastName: "Young", password: "boo" }]; var newData = { username: "001", firstName: "Ali", lastName: "Bound", password: "hello" }; var anotherNewData = { username: "001", firstName: "holyshit", lastName: "Bound", password: "hello" }; var dbName = "allData", dbVersion = 1, dbStoreName = "users"; var db; //初始化數(shù)據(jù)庫(kù) function initDb() { console.log("initDb..."); //初始化數(shù)據(jù)庫(kù)... var req = indexedDB.open(dbName, dbVersion); req.onsuccess = function() { db = this.result; console.log("initDb Done."); }; req.onerror = function() { console.log("initDb:", event.target.errorCode); }; req.onupgradeneeded = function() { console.log("initDb.onupgradeneeded"); var store = event.target.result.createObjectStore(dbStoreName, { keyPath: "username" }); //這里不能用db,而是event.target.result; store.createIndex("firstName", "firstName", { unique: false }); store.createIndex("lastName", "lastName", { unique: false }); }; } initDb(); //添加數(shù)據(jù) function addData(data) { console.log("add data..."); var req = indexedDB.open(dbName, dbVersion); req.onsuccess = function() { var transaction = db.transaction(dbStoreName, "readwrite"); var store = transaction.objectStore(dbStoreName); if (Object.prototype.toString.call(data).toString() === "[object Array]") { for (var i in data) { store.add(data[i]); } } else if (Object.prototype.toString.call(data).toString() === "[object Object]") { store.add(data); } else { console.log("adding data: please choose Array or Object."); } }; } addData(userData); //提取數(shù)據(jù) function getData(key, callback) { console.log("get data..."); var req = indexedDB.open(dbName, dbVersion); req.onsuccess = function() { var transaction = db.transaction(dbStoreName, "readonly"); var store = transaction.objectStore(dbStoreName); var data = store.get(key); data.onsuccess = function() { var result = event.target.result; if (result) { callback(result); console.log("get data done."); } }; }; } // getData("003", function (result) { // console.log(result); // }); //刪除數(shù)據(jù) function deleteData(key) { console.log("delete data..."); var req = indexedDB.open(dbName, dbVersion); req.onsuccess = function() { var transaction = db.transaction(dbStoreName, "readwrite"); var store = transaction.objectStore(dbStoreName); var data = store.delete(key); data.onsuccess = function() { console.log("delete data done."); }; }; } // deleteData("003"); //清空數(shù)據(jù) function clearData() { console.log("delete data..."); var req = indexedDB.open(dbName, dbVersion); req.onsuccess = function() { var transaction = db.transaction(dbStoreName, "readwrite"); var store = transaction.objectStore(dbStoreName); var data = store.clear(); data.onsuccess = function() { console.log("clear data done."); }; }; } // clearData(); //游標(biāo)提取數(shù)據(jù) function cursorGetData(key, callback) { console.log("cursor get data..."); var req = indexedDB.open(dbName, dbVersion); req.onsuccess = function() { var transaction = db.transaction(dbStoreName, "readonly"); var store = transaction.objectStore(dbStoreName); var cursor = store.openCursor(); cursor.onsuccess = function() { var cursor = event.target.result; if (cursor.key !== key) { cursor.continue(); } else { var result = cursor.value; callback(result); console.log("cursor get data done."); } }; }; } // cursorGetData("007", function (result) { // console.log(result); // }); //游標(biāo)修改數(shù)據(jù) function cursorUpdateData(key, property, newValue) { console.log("cursor update data..."); var req = indexedDB.open(dbName, dbVersion); req.onsuccess = function() { var transaction = db.transaction(dbStoreName, "readwrite"); var store = transaction.objectStore(dbStoreName); var cursor = store.openCursor(); cursor.onsuccess = function() { var cursor = event.target.result; if (cursor.key !== key) { cursor.continue(); } else { var target = cursor.value; for (var i in target) { if (i === property) { var value = Object.defineProperty(target, property, { value: newValue }); var updateReq = cursor.update(value); console.log("cursor update data done."); } } } }; }; } // cursorUpdateData("003", "firstName", "Ali"); //游標(biāo)刪除數(shù)據(jù) function cursorDeleteData(key) { console.log("cursor delete data..."); var req = indexedDB.open(dbName, dbVersion); req.onsuccess = function() { var transaction = db.transaction(dbStoreName, "readwrite"); var store = transaction.objectStore(dbStoreName); var cursor = store.openCursor(); cursor.onsuccess = function() { var cursor = event.target.result; if (cursor.key !== key) { cursor.continue(); } else { var deleteReq = cursor.delete(); console.log("cursor delete data done."); } }; }; } // cursorDeleteData("003"); //游標(biāo)遍歷所有項(xiàng) function cursorTraversalData(callback) { console.log("cursor tarversal data..."); var req = indexedDB.open(dbName, dbVersion); var result = []; req.onsuccess = function() { var transaction = db.transaction(dbStoreName, "readonly"); var store = transaction.objectStore(dbStoreName); var cursor = store.openCursor(); cursor.onsuccess = function() { var cursor = event.target.result; if (cursor) { result.push(cursor.value); cursor.continue(); } else { console.log("cursor traversal data done."); if (result.length > 0) { callback(result); } } }; }; } // cursorTraversalData(function (result) { // for (var i in result) { // console.log(JSON.stringify(result[i])); // } // }); //遍歷范圍內(nèi)所有項(xiàng) function boundTraversalData(lower, upper, boo1, boo2, callback) { console.log("bound tarversal data..."); var req = indexedDB.open(dbName, dbVersion); var result = []; req.onsuccess = function() { var transaction = db.transaction(dbStoreName, "readonly"); var store = transaction.objectStore(dbStoreName); var bound = IDBKeyRange.bound(lower, upper, boo1, boo2); var cursor = store.openCursor(bound); cursor.onsuccess = function() { var cursor = event.target.result; if (cursor) { result.push(cursor.value); cursor.continue(); } else { console.log("bound traversal data done."); if (result.length > 0) { callback(result); } } }; }; } // boundTraversalData("003", "007", true, true, function(result) { // for (var i in result) { // console.log(JSON.stringify(result[i])); // } // }); //索引中取得對(duì)象 function indexGetData(index, key, callback) { console.log("index get data..."); var req = indexedDB.open(dbName, dbVersion); req.onsuccess = function() { var transaction = db.transaction(dbStoreName, "readonly"); var store = transaction.objectStore(dbStoreName); var target = store.index(index); var data = target.get(key); data.onsuccess = function() { var result = event.target.result; if (result) { callback(result); console.log("index get data done."); } else { console.log("index get data: error output."); } }; }; } // indexGetData("firstName", "Alice", function (result) { // console.log(result); // }); //索引中取得主鍵 function indexGetKey(index, key, callback) { console.log("index get data..."); var req = indexedDB.open(dbName, dbVersion); req.onsuccess = function() { var transaction = db.transaction(dbStoreName, "readonly"); var store = transaction.objectStore(dbStoreName); var target = store.index(index); var data = target.getKey(key); data.onsuccess = function() { var result = event.target.result; if (result) { callback(result); console.log("index get key done."); } else { console.log("index get key: error output."); } }; }; } // indexGetKey("firstName", "Alice", function (result) { // console.log(result); // }); //訪問(wèn)所有索引 function getAllIndex(callback) { console.log("get all index..."); var req = indexedDB.open(dbName, dbVersion); req.onsuccess = function() { var transaction = db.transaction(dbStoreName, "readonly"); var store = transaction.objectStore(dbStoreName); var indexNames = store.indexNames; if (indexNames.length) { for (var i = 0, len = store.indexNames.length; i < len; i++) { var index = store.index(indexNames[i]); callback(index); } } }; } // getAllIndex(function (index) { // console.log(index.name); // console.log(index.keyPath); // console.log(index.objectStore.name); // console.log(index.unique); // });
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/78915.html
摘要:在線離線應(yīng)用緩存就是一個(gè)從瀏覽器的緩存中分出來(lái)的緩存去,在緩存中保存數(shù)據(jù),可以使用一個(gè)描述文件,列出要下載和緩存的資源。 離線檢測(cè) HTML5中定義的: navigator.onLine如果為true則表示設(shè)備能夠上網(wǎng) 注意是大寫(xiě)的L(onLine); 用下面代碼檢測(cè)屬性狀態(tài): if (navigator.onLine) { // statement if online } e...
摘要:字節(jié)流這個(gè)簡(jiǎn)單的模型將數(shù)據(jù)存儲(chǔ)為長(zhǎng)度不透明的字節(jié)字符串變量,將任何形式的內(nèi)部組織留給應(yīng)用層。字節(jié)流數(shù)據(jù)存儲(chǔ)的代表例子包括文件系統(tǒng)和云存儲(chǔ)服務(wù)。使用同步存儲(chǔ)會(huì)阻塞主線程,并為應(yīng)用程序的創(chuàng)建凍結(jié)體驗(yàn)。 這是專門(mén)探索 JavaScript 及其所構(gòu)建的組件的系列文章的第 16 篇。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來(lái)篇優(yōu)質(zhì)文章等著你! 如果你錯(cuò)過(guò)了前面的章節(jié),可以在這里找到它...
摘要:應(yīng)用緩存的應(yīng)用緩存,或者簡(jiǎn)稱為,是專門(mén)為開(kāi)發(fā)離線應(yīng)用而設(shè)計(jì)的。應(yīng)用緩存還有很多相關(guān)的事件,表示其狀態(tài)的改變。數(shù)據(jù)存儲(chǔ),通常直接叫做,最初是在客戶端用于存儲(chǔ)會(huì)話信息的。也就是使用值來(lái)存儲(chǔ)多個(gè)名稱值對(duì)兒。 所謂Web離線應(yīng)用,就是在設(shè)備不能上網(wǎng)的情況下仍然可以運(yùn)行的應(yīng)用。開(kāi)發(fā)離線Web應(yīng)用需要幾個(gè)步驟:(1)確保應(yīng)用知道設(shè)備是否能上網(wǎng);(2)應(yīng)用還必須能訪問(wèn)一定的資源(圖像、JavaScr...
摘要:離線檢測(cè)含義設(shè)備能否上網(wǎng)代碼注和,和最新的沒(méi)問(wèn)題應(yīng)用緩存緩存的目的是專門(mén)為網(wǎng)頁(yè)離線設(shè)計(jì)的,當(dāng)然在在線情況也會(huì)緩存機(jī)制當(dāng)用戶在地址輸入請(qǐng)求的地址去請(qǐng)求網(wǎng)頁(yè)時(shí),瀏覽器會(huì)先本地緩存中查看是否有對(duì)應(yīng)的緩存文件,如果有然后查看新鮮度就是是否過(guò)期了,如 23.1 離線檢測(cè) 含義:設(shè)備能否上網(wǎng) 代碼: navigator.onLine 注:IE6+和safari+5,firefox3+和ope...
摘要:離線應(yīng)用與客戶端存儲(chǔ)離線檢測(cè)定義了屬性來(lái)檢測(cè)設(shè)備是在線還是離線。應(yīng)用緩存還有很多相關(guān)的事件,表示其狀態(tài)的改變。 離線應(yīng)用與客戶端存儲(chǔ) 離線檢測(cè) HTML5定義了navigator.onLine屬性來(lái)檢測(cè)設(shè)備是在線還是離線。這個(gè)屬性為true表示設(shè)備能上網(wǎng),值為false表示設(shè)備離線。這個(gè)屬性的關(guān)鍵是瀏覽器必須知道設(shè)備能否訪問(wèn)網(wǎng)絡(luò),從而返回正確的值 不同瀏覽器之間有小差異 IE6+...
閱讀 864·2021-08-23 09:46
閱讀 1069·2019-08-30 15:44
閱讀 2675·2019-08-30 13:53
閱讀 3126·2019-08-29 12:48
閱讀 4006·2019-08-26 13:46
閱讀 1911·2019-08-26 13:36
閱讀 3607·2019-08-26 11:46
閱讀 1523·2019-08-26 10:48