因爲瀏覽器存在各類限制,最好將整個cookie長度限制在4095B之內。javascript
cookie由瀏覽器保存的如下幾塊信息構成:css
名稱: cookie的名稱必須是通過URL編碼後的字符串。 雖然它是不區分大小寫的, 可是實際應用時建議把它看成區分大小寫來使用。html
值: cookie中字符串值, 也必須是通過URI編碼的字符串。java
域: 表示cookie對於哪一個域有效。ios
路徑: cookie是針對域中的哪一個目錄生效。web
失效時間: 表示cookie失效時間的時間戳, 它是GMT格式的日期。 將該事件設置小於當前時, 就至關於刪除了cookie。chrome
安全標識: 指定該標識後, 只有使用SSL請求鏈接的時候cookie纔會發送到服務器。 secure標識是cookie中惟一一個非鍵值對的部分, 它只包含一個secure單詞。數據庫
使用分號加空格分開各個信息構成:windows
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
或使用安全標誌:數組
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中能夠經過
document.cookie
能夠讀取當前域名下的cookie, 是用分號隔開的鍵值對構成的字符串。 相似於name = aa;
age = 15;
注意全部的鍵值對名稱和值都是通過encodeURIComponent()
編碼的, 使用時要進行解碼。
當給document.cookie賦值時, 不會直接覆蓋現有的cookie, 而是會追加一個新的cookie。 例如:
document.cookie = "a=1"; //執行後會看到新增了一個cookie。
如:
document.cookie = encodeURIComponent("name") + "=" + encodeURIComponent("Oliver"); console.log(document.cookie); //name=Oliver;
若是給cookie賦值則會增長一個cookie:
document.cookie = encodeURIComponent("name") + "=" + encodeURIComponent("Oliver"); document.cookie = encodeURIComponent("age") + "=" + encodeURIComponent("18"); console.log(document.cookie); //name=Oliver; age=18
如下函數是經常使用的cookie讀寫刪除方法:
var CookieUtil = { //根據key讀取cookie get: function(name) { //注意對鍵編碼 var cookieName = encodeURIComponent(name) + "=", cookieStart = document.cookie.indexOf(cookieName), cookieValue = null, cookieEnd; //找到cookie鍵 if (cookieStart > -1) { //鍵後面第一個分號位置 cookieEnd = document.cookie.indexOf(";", cookieStart); if (cookieEnd == -1) { cookieEnd = document.cookie.length; } //cookie值解碼 cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd)); } return cookieValue; }, //設置cookie set: function(name, value, expires, path, domain, secure) { var cookieText = encodeURIComponent(name) + "=" + encodeURIComponent(value); //失效時間,GMT時間格式 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,保持相同的鍵、域、路徑、安全選項,而後設置失效時間便可 unset: function(name, path, domain, secure) { this.set(name, "", new Date(0), path, domain, secure); } };
能夠像下面這樣使用上述方法:
設置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
設置cookie路徑、域等:
CookieUtil.set("name","Oliver","/","localhost",null,false);
不然使用下面的代碼建立和刪除cookie:
//新cookie document.cookie = encodeURIComponent("name") + "=" + encodeURIComponent("Oliver"); //刪除上面建立的cookie document.cookie = encodeURIComponent("name") + "=" + encodeURIComponent("Oliver") + "; expires=" + new Date(0);
舉例
css:
<style type="text/css"> *{ margin: 0; padding: 0; } div#message { border: 1px solid #ccc; min-height: 3em; background-color: #33CCFF; margin: 0; } p#content{ color:white; font-size: 2em; margin:0.3em; font-family: monospace; display: inline-block; float: left; /*border: 1px solid gray;*/ } a#notShow { width: 2em; display: block; height: 1em; float: right; /*border: 1px solid gray;*/ } </style>
DOM:
<div id="message"> <p id="content">welcome to my site!</p> <a href="" id="notShow">關閉</a> </div>
js:
<script type="text/javascript"> //CookieUtil函數 var CookieUtil = {...} //獲取元素 var messageDiv = document.getElementById("message"); var notShowBtn = document.getElementById("notShow"); //點擊關閉按鈕新建cookie並關閉banner notShowBtn.onclick = function () { event.preventDefault(); CookieUtil.set("hideMessage", "hide"); messageDiv.style.display = "none"; }; //檢查cookie當存在則關閉banner window.onload = function () { if (CookieUtil.get("hideMessage")) { messageDiv.style.display = "none"; } }; </script>
因爲瀏覽器cookie數量是有限制的,爲了減小cookie數量可使用子cookie的方式。在一個cookie值中使用相似查詢字符串的格式能夠存儲多組鍵值對,這樣就沒必要每一個鍵值對都佔用一個cookie了。子cookie值舉例:
name=name1=value1&name2=value2
獲取全部子cookie並將它放在一個對象中返回,對象的屬性名爲子cookie名稱,對象的屬性值爲子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值分隔成數組 subCookies = cookieValue.split("&"); for (i = 0, len = subCookies.length; i < len; i++) { //等號分隔出鍵值對 parts = subCookies[i].split("="); //將解碼後的兼職對分別做爲屬性名稱和屬性值賦給對象 result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]); } return result; } } return null; }
get()獲取單個子cookie。
get: function(name, subName) { //獲取全部子cookie var subCookies = this.getAll(name); if (subCookies) { //從屬性中獲取單個子cookie return subCookies[subName]; } else { return null; } }
setAll設置整個cookie
setAll: function(name, subcookies, expires, path, domain, secure) { var cookieText = encodeURIComponent(name) + "=", subcookieParts = new Array(), subName; //遍歷子cookie對象的屬性 for (subName in subcookies) { //要先檢測屬性名 if (subName.length > 0 && subcookies.hasOwnProperty(subName)) { //屬性名和屬性值編碼後=鏈接爲字符串,並放到數組中 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(); } //設置整個cookie document.cookie = cookieText; }
set設置單個子cookie
set: function(name, subName, value, expires, path, domain, secure) { //獲取當前cookie對象 var subcookies = this.getAll(name) || {}; //單個cookie對應的屬性替換 subcookies[subName] = value; //從新設置cookie this.setAll(name, subcookies, expires, path, domain, secure); }
刪除整個cookie, 將失效時間設置爲過時日期便可。
unsetAll: function(name, path, domain, secure) { this.setAll(name, null, new Date(0), path, domain, secure); }
刪除單個子cookie,須要先獲取全部子cookie對象,而後刪除子cookie對應的屬性,最後再將子cookie對象從新設置回去。
unset: function(name, subName, path, domain, secure) { //獲取當前cookie對象 var subcookies = this.getAll(name); if (subcookies) { //刪除子cookie對應的屬性 delete subcookies[subName]; //從新設置cookie this.setAll(name, subcookies, null, path, domain, secure); } }
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值分隔成數組 subCookies = cookieValue.split("&"); for (i = 0, len = subCookies.length; i < len; i++) { //等號分隔出鍵值對 parts = subCookies[i].split("="); //將解碼後的兼職對分別做爲屬性名稱和屬性值賦給對象 result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]); } return result; } } return null; }, get: function(name, subName) { //獲取全部子cookie var subCookies = this.getAll(name); if (subCookies) { //從屬性中獲取單個子cookie return subCookies[subName]; } else { return null; } }, setAll: function(name, subcookies, expires, path, domain, secure) { var cookieText = encodeURIComponent(name) + "=", subcookieParts = new Array(), subName; //遍歷子cookie對象的屬性 for (subName in subcookies) { //要先檢測屬性名 if (subName.length > 0 && subcookies.hasOwnProperty(subName)) { //屬性名和屬性值編碼後=鏈接爲字符串,並放到數組中 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(); } //設置整個cookie document.cookie = cookieText; }, set: function(name, subName, value, expires, path, domain, secure) { //獲取當前cookie對象 var subcookies = this.getAll(name) || {}; //單個cookie對應的屬性替換 subcookies[subName] = value; //從新設置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) { //獲取當前cookie對象 var subcookies = this.getAll(name); if (subcookies) { //刪除子cookie對應的屬性 delete subcookies[subName]; //從新設置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 //獲取單個子cookie data = SubCookieUtil.get("data", "name"); console.log(data); //Oliver console.log(document.cookie); //data=name=Oliver&book=jsbook
設置cookie:
//若cookie爲document.cookie=data=name=Oliver&book=jsbook; document.cookie = "data" + "=" + "name" + "=" + "Oliver" + "&" + "book" + "=" + "jsbook"; //設置兩個cookie SubCookieUtil.set("data", "name", "Nicholas"); SubCookieUtil.set("data", "book", "HTMLreference") console.log(document.cookie); //data=name=Nicholas&book=HTMLreference //設置所有子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.]
舉例:
多個提醒banner的「再也不提醒功能」存在同一個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部分:
<div id="message"> <p class="content">welcome to my site!<a href="" class="notShow">shotdown</a></p> <p class="content">click to close this banner.<a href="" class="notShow">close</a></p> </div>
js部分:
//獲取元素 var notShowBtn = document.getElementsByClassName("notShow"); //點擊關閉按鈕新建cookie並關閉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當存在則關閉banner window.onload = function() { notShowBtnList.forEach(function(element, index) { var value = "content" + element; if (SubCookieUtil.get("hideMessage", value)) { notShowBtn[element].parentNode.style.display = "none"; } }); };
用如下代碼:
<div style="behavior:url(#default#userData)" id="dataStore"></div>
而後利用setAttribute()方法保存數據
再調用save()
方法保存到指定的數據空間
下一次頁面載入後就可使用load()
方法讀取數據
最初的Web Storage規範包含了兩種對象的定義:sessionStorage
和globalStorage
,這兩種都是在windows對象屬性中存在的。
該類型提供最大的存儲空間來存儲名值對,有一下方法:
clear()
刪除全部值;
key(index)
得到index處的名字;
getItem(name)
根據指定的name獲取對應的值;
removeItem(name)
刪除name處的名值對;
setItem(name, value)
爲指定的name設置一個對應的值;
其中後三中能夠直接調用也能夠經過Storage對象間接調用。
還可使用length屬性來判斷有多少名值對兒存放在Storage對象中,但沒法判斷對象中全部數據的大小,不過IE8提供了一個remainingSpace屬性,用於獲取還可使用的存儲空間的字節數。
sessionStorage對象存儲特定於某個會話的數據,也就是該數據只保持到該瀏覽器關閉。存儲在sessionStorage中的數據能夠跨越頁面刷新而存在,同時若是瀏覽器支持,瀏覽器崩潰並重啓以後依然可用(Firefox和WebKit都支持,IE則不行)。存儲在sessionStorage中的數據只能由最初給定對象存儲數據的頁面訪問到,因此對頁面應用有限制。
可使用setItem()或者直接設置新的屬性來存儲數據。下面是這兩種方法的例子。
sessionStorage.setItem("name", "Oliver"); //使用方法存儲數據 sessionStorage.book = "JSON.com"; //使用屬性存儲數據
Firefox和Webkit實現了同步寫入,因此添加到存儲空間中的數據是馬上被提交的。而IE的實現則是異步寫入數據,因此在設置數據和將數據實際寫入磁盤之間可能有一些延遲。
在IE8中能夠強制把數據寫入磁盤:在設置新數據以前使用
begin()
方法
而且全部設置完成以後調用
commit()
方法
看如下例子:
sessionStorage.begin(); sessionStorage.name = "oli"; sessionStorage.commit();
getItem()
可使用getItem()或者經過直接訪問屬性名來獲取數據。
sessionStorage.name = "oli"; sessionStorage.age = 18; var val = sessionStorage.name; var val_1 = sessionStorage.age; console.log(val); //oli console.log(val_1); //18
key()
方法
經過結合length屬性和key()方法來迭代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循環來迭代sessionStorage中的值:
for (key in sessionStorage) { var value = sessionStorage.getItem(key); console.log(key + "=" + value); }
removeItem()
方法
要從sessionStorage中刪除數據,可使用delete操做符刪除對象屬性,也可調用removeItem()方法。
sessionStorage.name = "oli"; sessionStorage.age = 18; sessionStorage.removeItem("name"); delete sessionStorage.age;
sessionStorage對象應該主要用於僅針對會話的小段數據的存儲。
Firefox 2中實現了globalStorage對象。做爲最初的Web Storage規範的一部分,這個對象的目的是跨越會話存儲數據,但有特定的訪問限制。要使用globalStorage,首先要指定哪些域能夠訪問該數據。能夠經過方括號標記使用屬性來實現,如如下例子所示。
globalStorage["test.com"].name = "Oliver"; var name = globalStorage["test.com"].name;
其中,globalStorage不是Storage的實例,globalStorage["test.com"]纔是
某些瀏覽器容許更加寬泛的訪問限制,好比只根據頂級域名進行限制或者容許全局訪問,以下面例子所示:
//存儲數據,任何人均可以訪問——不要這樣作! globalStorage[""].name = "Nicholas"; //存儲數據,可讓任何以.net結尾域名訪問——不要這樣作! globalStorage["net"].name = "Nicholas";
要避免使用這種可寬泛訪問的數據存儲
對globalStorage空間的訪問,是一句發起請求的頁面的域名、協議和端口來限制的。例如,若是使用HTTPS協議在w3cmm.com中存儲了數據,那麼經過HTTP訪問的w3cmm.com的頁面就不能訪問該數據。
globalStorage的每一個屬性都是Storage的實例。所以,能夠像以下代碼中這樣使用。
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對象在修訂過的HTML5規範中做爲持久保存在客戶端數據的方案取代了globalStorage。要訪問同一個localStorage對象,頁面必須來自同一個域名(子域名無效),使用同一種協議,在同一個端口上。這至關於globalStorage[location.host]。
因爲localStorage是Storage的實例,因此能夠像使用sessionStorage同樣來使用它。下面是一些例子。
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對象進行任何修改,都會在文檔上觸發storage事件。當經過屬性或setItem()方法保存數據,使用delete操做符或removeItem()刪除數據,或着調用clear()方法時,都會發生該事件。這個事件的event對象有如下屬性。
domain
:發生變化的存儲空間的域名。
key
:設置或着刪除的鍵名。
newValue
:若是是設置值,則是新值;若是是刪除鍵,則是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); });
與其它客戶端數據存儲方案相似,Web Storage一樣也有限制。這些限制因瀏覽器而異。通常來講,對存儲空間大小的限制都是以每一個來源(協議、域和端口)爲單位的。
對於localStorage而言,大多數桌面瀏覽器會設置每一個來源5MB的限制。Chrome和Safari對每一個來源的限制是2.5MB。而ios版Safari和Android版Webkit的限制也是2.5MB。
對sessionStorage的限制也是因瀏覽器而異。有的瀏覽器對sessionStorage的大小沒有限制,但Chrome、Safari、ios版Safari和Android版Webkit都有限制,也都是2.5MB。IE8+和Opera對sessionStorage的限制是5MB。
推薦一篇文章使用 IndexedDB,來自MDN,連接地址:https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API/Using_IndexedDB
Indexed Database API 簡稱爲IndexedDB,是在瀏覽器中保存結構化數據的一種數據庫。
設計思想是創建一套API,方便保存和讀取JavaScript對象,同時還支持查詢和搜索。
該操做徹底是異步進行的。
差很少每一次IndexedDB操做,都須要註冊onerror或onsuccess事件處理程序,以確保適當地處理結果。
在使用時須要加上瀏覽器提供商前綴:
var indexDB = window.indexedDB || window.msIndexedDB || window.mozIndexedDB || window.webkitIndexedDB;
indexDB.open()
IndexedDB就是一個數據庫,IndexedDB最大的特點是使用對象保存數據,而不是使用表來保存數據。
使用IndexedDB前首先要打開它,即把要打開的數據庫名傳給indexDB.open()
。若是傳入的數據庫已經存在,就會發送一個打開它的請求;若是傳入的數據庫還不存在,就會發送一個建立並打開它的請求;
總之,調用indexedDB.open()會返回一個IDBRequest對象,在這個對象上能夠添加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 {} 指向數據庫實例對象 console.log(event.target); //IDBOpenDBRequest {} 指向request對象 };
ABORT_ERR
錯誤碼8 : A request was aborted,
example, through a call to IDBTransaction.abort.
CONSTRAINT_ERR
錯誤碼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
錯誤碼5 : Data provided to an operation does not meet requirements.
NON_TRANSIENT_ERR
錯誤碼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
錯誤碼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
錯誤碼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
錯誤碼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
錯誤碼9 : A mutation operation was attempted in a READ_ONLY transaction.
TIMEOUT_ERR
錯誤碼10 : A lock
the transaction could not be obtained in a reasonable time.
TRANSACTION_INACTIVE_ERR
錯誤碼7 : A request was made against a transaction that is either not currently active or is already finished.
UNKNOWN_ERR
錯誤碼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
錯誤碼12 : A request to open a database with a version lower than the one it already has.This can only happen with IDBOpenDBRequest.
indexedDB.setVersion()
設置版本號
indexedDB.version
獲取版本號
默認狀況下,IndexedDB數據庫是沒有版本號的。最好一開始就調用setVersion()
方法爲數據庫指定一個版本號(傳入一個表示版本號的字符串)。
目前就chrome瀏覽器,版本號方法已再也不適用,另外,建立database後chrome瀏覽器自動設置版本號爲"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 };
要更新數據庫的 schema,也就是建立或者刪除對象存儲空間,須要實現 onupgradeneeded 處理程序,這個處理程序將會做爲一個容許你處理對象存儲空間的 versionchange 事務的一部分被調用。
request.onupgradeneeded
如:
// 該事件僅在較新的瀏覽器中被實現 request.onupgradeneeded = function(event) { // 更新對象存儲空間和索引 .... };
如需設置數據庫版本號,用下面方法:(舊)
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 }; };
創建完數據庫鏈接之後,就要建立對象存儲空間。
鍵的提供能夠有幾種不一樣的方法,這取決於對象存儲空間是使用 key path 仍是 key generator。
若要保存用戶記錄由用戶名、密碼組成,那麼保存一條記錄的對象應該以下所示:
var userData = [{ username: "007", firstName: "James", lastName: "Bond", password: "foo" }, { username: "005", firstName: "Oliver", lastName: "Young", password: "boo" }];
其中username爲鍵(keyPath),這個應該是全局惟一的(表明一個user)。
下面是爲了保存用戶記錄而建立對象存儲空間的示例:
var request = indexedDB.open("Base", 2); //注意填寫版本號 request.onerror = function() { console.log(event.target.errorCode); }; request.onupgradeneeded = function() { var database = event.target.result; var store = database.createObjectStore("users", { keyPath: "username" }); //根據username建立一個名爲users的對象集合(表) };
得到了對象存儲空間的引用以後,就可使用
add()
或put()
方法向其中添加數據
這兩個方法都接收一個參數,即要保存的對象,而後這個對象就會被保存到存儲空間中。
這兩個方法的區別在於,若是空間中已經包含了鍵值相同的對象:add()會返回錯誤;put()則會重寫原有對象;
可使用下面的代碼初始化(add()方法)存儲空間:
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循環可用下面代碼代替:
//users中保存着一批的用戶對象 var i = 0, request, requests[], len = users.length; while (i < len) { request = store.add(users[i++]); request.onerror = function() { // 錯誤處理 }; request.onsuccess = function() { // 成功 }; requests.push(request); }
如下爲完整的建立數據庫和存儲空間以及初始化數據的代碼例子:
// //數據在這裏userData // var userData = [{ username: "007", //username惟一 firstName: "James", lastName: "Bond", password: "foo" }, { username: "005", firstName: "Oliver", lastName: "Young", password: "boo" }]; // //建立數據庫Alldata // var request = indexedDB.open("allData"); request.onerror = function() { console.log(event.target.errorCode); }; request.onsuccess = function() { var database = event.target.result; console.log("數據庫已經建立:" + database.name + "; 版本號:" + database.version); }; // //建立存儲空間(表)users,並初始化數據 // var request = indexedDB.open("allData", 2); request.onupgradeneeded = function() { var database = event.target.result; //建立存儲空間 var store = database.createObjectStore("users", { keyPath: "username" }); //添加數據 for (var i in userData) { store.add(userData[i]); } };
另外,下面是數據庫結構:
indexedDB |-allData數據庫 |-users存儲空間(表) |-(userData數據)
在數據庫對象上調用transaction()方法就能夠建立事務。任什麼時候候,想要讀取或修改數據,都要經過事務來組織全部的操做。
下面的代碼保證只加載users存儲空間中的數據,以便經過事務進行訪問:
var transaction = database.transaction("users");
要訪問多個對象存儲空間,能夠傳入字符串數組:
var transaction = db.transaction(["users", "anotherStore"]);
上面的兩個事務都是以只讀的方式訪問數據。要修改訪問方式,必須在建立事務時傳入第二個參數。
默認都是以只讀的方式訪問數據,要修改訪問方式,必須傳入第二個參數,這個參數表示訪問模式:
READ_ONLY(0)
表示只讀;
READ_WRITE(1)
表示讀寫;
VERSION_CHANGE(2)
表示改變
注意: 舊版實驗性的實現使用不建議使用的常量 IDBTransaction.READ_WRITE 而不是 "readwrite"。
因此如今通常表示讀寫應該傳入字符串"readwrite"
其中,上面三個訪問模式已經被改成:
"readonly"
只讀;
"readwrite"
讀寫;
以下:
var request = database.transaction("users", "readonly");
objectStore()
方法,並傳入存儲空間的名稱,就能夠訪問特定的存儲空間了。
就能夠:
使用add()和put()方法添加數據;
使用get()能夠取得值;
使用delete()能夠刪除對象;
使用clear()能夠刪除全部對象;
get()和delete()方法都接收一個對象鍵做爲參數。全部的這5個方法都會返回一個新的請求對象。例如:
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");
事務自己也有事件處理程序:onerror
和oncomplete
。
這兩個事件能夠提供事務級的狀態信息。
注意:經過oncomplete事件的事件對象訪問不到get()請求返回的任何數據,必須在onsuccess事件處理程序中才能訪問到。
如下爲實例:
var userData = [{ username: "007", //username惟一 firstName: "James", lastName: "Bond", password: "foo" }, { username: "005", firstName: "Oliver", lastName: "Young", password: "boo" }]; //建立數據庫Alldata var request = indexedDB.open("allData"); request.onerror = function() { console.log(event.target.errorCode); }; request.onsuccess = function() { var database = event.target.result; console.log("數據庫已經建立:" + database.name + "; 版本號:" + database.version); }; //建立存儲空間(表)users並初始化數據 var request = indexedDB.open("allData", 2); var database; request.onupgradeneeded = function() { database = event.target.result; //建立存儲空間 var store = database.createObjectStore("users", { keyPath: "username" }); //添加數據 for (var i in userData) { store.add(userData[i]); } }; var newPerson = { username: "001", firstName: "Troy", lastName: "Ruby", password: "hello" }; //事務 var request = indexedDB.open("allData", 2); request.onsuccess = function () { var database = event.target.result; // var request = database.transaction("users").objectStore("users").add(newPerson); //報錯,由於只讀,須要設置爲"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"); };
遊標就是指向結果集的一個指針,在對象存儲空間上調用;在須要檢索多個對象的狀況下,須要在事務內部建立遊標。注意,必須在事務內部建立!
openCursor()
方法能夠建立遊標。
openCursor()方法返回的也是一個請求對象,也須要爲該對象指定onsuccess和onerror事件處理函數
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) { // 處理失敗 };
在前面的onsuccess事件處理程序執行時,能夠經過event.target.result
取得存儲空間中的下一個對象。
IDBCursor
實例具備如下幾個屬性:
key
: 對象的鍵;
value
:實際的對象;
direction
:數值,表示遊標走動的方向。
默認是IDBCursor.NEXT(0)
, 表示下一項。
IDBCursor.NEXT_TO_DUPLICATE(1)
, 表示下一個不重複的項;
IDBCursor.PREV(2)
表示前一項;
IDBCursor.PREV_NO_DUPLICATE
表示前一個不重複的項。
primaryKey
:遊標使用的鍵,有多是對象鍵,也有多是索引鍵(後面會討論索引)
要檢索某個信息的結果,以下代碼:
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是一個對象,必要時須要用到JSON.stringify方法
update()
方法更新記錄
調用update()方法可使用指定的對象更新當前遊標的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); //遊標在第一個位置」005「因此他的firstName就是"Oliver"; 刷新瀏覽器,顯示的結果則爲Oli var value = cursor.value; //更改當前遊標所指的對象("005")的firstName爲"Oli"; value.firstName = "Oli"; var updateRequest = cursor.update(value); //使用update方法請求保存更新 updateRequest.onerror = function () { console.log(event.target.errorCode); }; updateRequest.onsuccess = function () { console.log("success"); //success }; } } }; transaction.onerror = function() { console.log(event.target.errorCode); };
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(); //請求刪除此項 deleteRequest.onerror = function () { // body... }; deleteRequest.onsuccess = function () { // body... }; } } };
注意:若是當前的事務沒有修改對象存儲空間的權限,update()和delete()會拋出錯誤。
默認狀況下每一個遊標只發起一次請求;要想發起另外一次請求,必須調用下面的一個方法:
continue(key)
: 移動到結果集的下一項。參數key是可選的,不指定這個參數,遊標移動到下一項;指定這個參數的話,遊標會移動到指定鍵的位置。
advance(count)
: 向前移動count指定的項數。
使用移動遊標的方法,能夠用來遍歷存儲空間中的全部項:
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(); //移動下一項 } else { console.log("done"); } };
調用continue()會觸發另外一次請求,進而再次調用onsuccess處理程序。若是沒有更多項能夠遍歷時,event.target.result的值爲null。
鍵範圍由IDBKeyRange的實例表示。
有四中定義鍵範圍的方式:
var onlyrange = IDBKeyRange.only("007"); var transaction = database.transaction("users", "readwrite").objectStore("users").openCursor(onlyrange);
將onlyrange變量傳入openCursor方法中
第二種定義鍵範圍的方法是指定結果集的下界。下界表示遊標開始的位置。
若是想要忽略鍵爲"007"的對象自己,從它的下一個對象開始,能夠傳入第二個參數true:
var lowerBound = IDBKeyRange.lowerBound("003", true); //第二個參數爲true表示不包括003 var transaction = database.transaction("users", "readwrite").objectStore("users").openCursor(lowerBound);
第三種定義鍵範圍的方法是指定結果集的上界,也就是指定遊標不能超過哪一個鍵。
若是不想包含鍵爲指定值的對象,一樣傳入第二個參數true:
var upperBound = IDBKeyRange.upperBound("005", true); //第二個參數爲true表示不包括005 var transaction = database.transaction("users", "readwrite").objectStore("users").openCursor(upperBound);
使用bound()方法能夠同時指定上下界。
這個方法能夠接收四個參數:表示下界的鍵,表示上界的鍵,可選的表示是否跳過下界的布爾值和可選的表示是否跳過上界的布爾值。
var bound = IDBKeyRange.bound("003", "005", true, false); //第三和第四個參數爲true和false表示不包括003包括005 var transaction = database.transaction("users", "readwrite").objectStore("users").openCursor(bound);
openCursor()能夠接收兩個參數,一個是剛纔的IDBKeyRange實例,第二個是表示方向的數值常量,也就是前面講到的IDBCursor中的常量。
正常狀況下,遊標都是從存儲空間的第一項開始,調用continue()或advance()前進到最後一項。遊標的默認方向值是
IDBCursor.NEXT
或IDBCursor.NEXT_NO_DUPLICATE
IDBCursor.next
或IDBCursor.nextunique
也能夠建立一個遊標,從最後一個對象開始,逐個迭代,直到第一個對象,這時要傳入的常量是:
IDBCursor.PREV
或IDBCursor.PREV_NO_DUPLICATE
IDBCursor.prev
或IDBCursor.prevunique
對於有些數據,須要建立多個鍵,如把用戶ID做爲主鍵,以用戶名建立索引
首先引用對象存儲空間,而後調用
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 }); //建立名爲firstName的索引,屬性名爲firstName,屬性值非惟一 };
index()
方法
以下:
var index = database.transaction("users").objectStore("users").index("firstName"); console.log(index); //IDBIndex對象
openCursor()
方法
以下:
var request = index.openCursor(); request.onsuccess = function () { console.log(event.target.result); //IDBCursorWithValue對象 };
遍歷:
var request = index.openCursor(); request.onsuccess = function() { var cursor = event.target.result; //IDBCursorWithValue對象 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 };
openKeyCursor()
方法
調用這個特殊的只返回每條記錄主鍵的遊標,這個方法在event.result.key中保存索引鍵,在event.result.value中保存的則是主鍵,而不是整個對象
get()
方法
只要傳入相應的索引鍵便可:
var store = db.transaction("users").objectStore("users"); var index = store.index("firstName"); var request = index.get("007");
getKey()
方法
這個方法中event.result.value等於主鍵的值,而不是整個對象:
var store = db.transaction("users").objectStore("users"); var index = store.index("firstName"); var request = index.getKey("007");
name
:索引的名字
keyPath
:createIndex方法中屬性的路徑
objectStore
:索引的對象存儲空間
unique
:表示索引鍵是否惟一
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");
每次打開數據庫,都應該指定onversionchange事件處理程序:
request.onsuccess = function() { database = event.target.result; database.onversionchange = function () { database.close(); }; };
當設置version時,指定請求的onblocked事件處理程序也很重要:
var request = database.setVersion("2.0"); request.onblocked = function () { alert("輕先關閉其餘標籤頁後再嘗試"); }; request.onsuccess = function () { //處理成功,繼續 };
同源
多個限制5MB大小
Firefox不容許本地訪問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; //初始化數據庫 function initDb() { console.log("initDb..."); //初始化數據庫... 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(); //添加數據 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); //提取數據 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); // }); //刪除數據 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"); //清空數據 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(); //遊標提取數據 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); // }); //遊標修改數據 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"); //遊標刪除數據 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"); //遊標遍歷全部項 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])); // } // }); //遍歷範圍內全部項 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])); // } // }); //索引中取得對象 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); // }); //訪問全部索引 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); // });