亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

JavaScript 離線應(yīng)用與客戶端存儲(chǔ)——“數(shù)據(jù)存儲(chǔ)”的注意要點(diǎn)

dreamGong / 3066人閱讀

摘要:對(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-value
JavaScript中的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部分:

welcome to my site!shotdown

click to close this banner.close

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ì)象的定義:sessionStorageglobalStorage,這兩種都是在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ù)本身也有事件處理程序:onerroroncomplete。

這兩個(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.NEXTIDBCursor.NEXT_NO_DUPLICATE

IDBCursor.nextIDBCursor.nextunique

也可以創(chuàng)建一個(gè)游標(biāo),從最后一個(gè)對(duì)象開(kāi)始,逐個(gè)迭代,直到第一個(gè)對(duì)象,這時(shí)要傳入的常量是:

IDBCursor.PREVIDBCursor.PREV_NO_DUPLICATE

IDBCursor.prevIDBCursor.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

相關(guān)文章

  • JavaScript 離線應(yīng)用戶端存儲(chǔ)——“應(yīng)用緩存”注意要點(diǎn)

    摘要:在線離線應(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...

    vpants 評(píng)論0 收藏0
  • JavaScript是如何工作:存儲(chǔ)引擎+如何選擇合適存儲(chǔ)API

    摘要:字節(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é),可以在這里找到它...

    draveness 評(píng)論0 收藏0
  • JS學(xué)習(xí)筆記(第23章)(離線應(yīng)用戶端存儲(chǔ)1)

    摘要:應(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...

    fjcgreat 評(píng)論0 收藏0
  • javascript-離線應(yīng)用戶端存儲(chǔ)

    摘要:離線檢測(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...

    gecko23 評(píng)論0 收藏0
  • 高程3總結(jié)#第23章離線應(yīng)用戶端存儲(chǔ)

    摘要:離線應(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+...

    MobService 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<