离线应用与客户端存储

目录

1 离线检测

2 应用缓存

3 数据存储

3.2 IE用户数据

3.3 Web存储机制

3.4 IndexedDB


1 离线检测

开发离线应用的第一步是要知道设备是在线还是离线,HTML5为此定义了一个navigator.onLine 属性,这个属性值为 true 表示设备能上网,值为 false 表示设备离线。由于存在上述兼容性问题,单独使用 navigator.onLine 属性不能确定网络是否连通。即便如此, 在请求发生错误的情况下,检测这个属性仍然是管用的。以下是检测该属性状态的示例。

if (navigator.onLine){
 //正常工作
} else {
 //执行离线状态时的任务
} 

除 navigator.onLine 属性之外,为了更好地确定网络是否可用,HTML5 还定义了两个事件: online 和 offline。当网络从离线变为在线或者从在线变为离线时,分别触发这两个事件。这两个事 件在 window 对象上触发。

EventUtil.addHandler(window, "online", function(){
 alert("Online");
});
EventUtil.addHandler(window, "offline", function(){
 alert("Offline");
}); 

2 应用缓存

HTML5 的应用缓存(application cache),或者简称为 appcache,是专门为开发离线 Web 应用而设计 的。Appcache 就是从浏览器的缓存中分出来的一块缓存区。要想在这个缓存中保存数据,可以使用一个 描述文件(manifest file),列出要下载和缓存的资源。下面是一个简单的描述文件示例。

CACHE MANIFEST

#Comment

file.js

file.css

要将描述文件与页面关联起来,可以在中的 manifest 属性中指定这个文件的路径,例如:

<html manifest="/offline.manifest"> 

以上代码告诉页面,/offline.manifest 中包含着描述文件。这个文件的 MIME 类型必须是 text/cache-manifest①。

3 数据存储

随着 Web 应用程序的出现,也产生了对于能够直接在客户端上存储用户信息能力的要求。今天,cookie 只是在客户端存储数据的其中一种选项。

HTTP Cookie,通常直接叫做 cookie,最初是在客户端用于存储会话信息的。该标准要求服务器对 任意 HTTP 请求发送 Set-Cookie HTTP 头作为响应的一部分,其中包含会话信息。例如,这种服务器响 应的头可能如下:

HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value
Other-header: other-header-value 

这个 HTTP 响应设置以 name 为名称、以 value 为值的一个 cookie,名称和值在传送时都必须是 URL 编码的。浏览器会存储这样的会话信息,并在这之后,通过为每个请求添加 Cookie HTTP 头将信 息发送回服务器,如下所示:

GET /index.html HTTP/1.1
Cookie: name=value
Other-header: other-header-value 

发送回服务器的额外信息可以用于唯一验证客户来自于发送的哪个请求。

1. 限制

cookie 在性质上是绑定在特定的域名下的。当设定了一个 cookie 后,再给创建它的域名发送请求时, 都会包含这个 cookie。这个限制确保了储存在 cookie 中的信息只能让批准的接受者访问,而无法被其他 域访问。 由于 cookie 是存在客户端计算机上的,还加入了一些限制确保 cookie 不会被恶意使用,同时不会占 据太多磁盘空间。每个域的 cookie 总数是有限的,不过浏览器之间各有不同。如下所示。

浏览器中对于 cookie 的尺寸也有限制。大多数浏览器都有大约 4096B(加减 1)的长度限制。为了 最佳的浏览器兼容性,最好将整个 cookie 长度限制在 4095B(含 4095)以内。尺寸限制影响到一个域 下所有的 cookie,而并非每个 cookie 单独限制。

2. cookie 的构成

cookie 由浏览器保存的以下几块信息构成。

 名称:一个唯一确定 cookie 的名称。cookie 名称是不区分大小写的,所以 myCookie 和 MyCookie 被认为是同一个 cookie。然而,实践中最好将 cookie 名称看作是区分大小写的,因为某些服务器会这样处理 cookie。cookie 的名称必须是经过 URL 编码的。

 值:储存在 cookie 中的字符串值。值必须被 URL 编码。

 域:cookie 对于哪个域是有效的。所有向该域发送的请求中都会包含这个 cookie 信息。这个值 可以包含子域(subdomain,如www.wrox.com),也可以不包含它(如.wrox.com,则对于wrox.com 的所有子域都有效)。如果没有明确设定,那么这个域会被认作来自设置 cookie 的那个域。

 路径:对于指定域中的那个路径,应该向服务器发送 cookie。例如,你可以指定 cookie 只有从 http://www.wrox.com/books/ 中才能访问,那么 http://www.wrox.com 的页面就不会发 送 cookie 信息,即使请求都是来自同一个域的。

 失效时间:表示 cookie 何时应该被删除的时间戳(也就是,何时应该停止向服务器发送这个 cookie)。默认情况下,浏览器会话结束时即将所有 cookie 删除;不过也可以自己设置删除时间。 这个值是个 GMT 格式的日期(Wdy, DD-Mon-YYYY HH:MM:SS GMT),用于指定应该删除 cookie 的准确时间。因此,cookie 可在浏览器关闭后依然保存在用户的机器上。如果你设置的失 效日期是个以前的时间,则 cookie 会被立刻删除。

 安全标志:指定后,cookie 只有在使用 SSL 连接的时候才发送到服务器。例如,cookie 信息只 能发送给 https://www.wrox.com,而 http://www.wrox.com 的请求则不能发送 cookie。

每一段信息都作为 Set-Cookie 头的一部分,使用分号加空格分隔每一段,如下例所示

HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value; expires=Mon, 22-Jan-07 07:10:24 GMT; domain=.wrox.com
Other-header: other-header-value 

3. JavaScript 中的 cookie

由于 JavaScript 中读写 cookie 不是非常直观,常常需要写一些函数来简化 cookie 的功能。基本的 cookie 操作有三种:读取、写入和删除。它们在 CookieUtil 对象中如下表示。

var CookieUtil = {
 get: function (name){
 var cookieName = encodeURIComponent(name) + "=",
 cookieStart = document.cookie.indexOf(cookieName),
 cookieValue = null;
 if (cookieStart > -1){
 var cookieEnd = document.cookie.indexOf(";", cookieStart);
 if (cookieEnd == -1){
 cookieEnd = document.cookie.length;
 }
 cookieValue = decodeURIComponent(document.cookie.substring(cookieStart
 + cookieName.length, cookieEnd));
 }
 return cookieValue;
 },
 set: function (name, value, expires, path, domain, secure) {
 var cookieText = encodeURIComponent(name) + "=" +
 encodeURIComponent(value);
 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;
 },
 unset: function (name, path, domain, secure){
 this.set(name, "", new Date(0), path, domain, secure);
 }
}; 

CookieUtil.get()方法根据 cookie 的名字获取相应的值。它会在 document.cookie 字符串中查 找 cookie 名加上等于号的位置。如果找到了,那么使用 indexOf()查找该位置之后的第一个分号(表 示了该 cookie 的结束位置)。如果没有找到分号,则表示该 cookie 是字符串中的最后一个,则余下的字 符串都是 cookie 的值。该值使用 decodeURIComponent()进行解码并最后返回。如果没有发现 cookie, 则返回 null。

CookieUtil.set()方法在页面上设置一个 cookie,接收如下几个参数:cookie 的名称,cookie 的值, 可选的用于指定 cookie 何时应被删除的 Date 对象,cookie 的可选的 URL 路径,可选的域,以及可选的 表示是否要添加 secure 标志的布尔值。参数是按照它们的使用频率排列的,只有头两个是必需的。在 这个方法中,名称和值都使用encodeURIComponent()进行了URL编码,并检查其他选项。如果expires 参数是 Date 对象,那么会使用 Date 对象的 toGMTString()方法正确格式化 Date 对象,并添加到 expires 选项上。方法的其他部分就是构造 cookie 字符串并将其设置到 document.cookie 中。

没有删除已有 cookie 的直接方法。所以,需要使用相同的路径、域和安全选项再次设置 cookie,并 将失效时间设置为过去的时间。CookieUtil.unset()方法可以处理这种事情。它接收 4 个参数:要删 除的 cookie 的名称、可选的路径参数、可选的域参数和可选的安全参数。

这些参数加上空字符串并设置失效时间为 1970 年 1 月 1 日(初始化为 0ms 的 Date 对象的值),传 给 CookieUtil.set()。这样就能确保删除 cookie。 可以像下面这样使用上述方法。

//设置 cookie
CookieUtil.set("name", "Nicholas");
CookieUtil.set("book", "Professional JavaScript");
//读取 cookie 的值
alert(CookieUtil.get("name")); //"Nicholas"
alert(CookieUtil.get("book")); //"Professional JavaScript"
//删除 cookie
CookieUtil.unset("name");
CookieUtil.unset("book");
//设置 cookie,包括它的路径、域、失效日期
CookieUtil.set("name", "Nicholas", "/books/projs/", "www.wrox.com",
 new Date("January 1, 2010"));
//删除刚刚设置的 cookie
CookieUtil.unset("name", "/books/projs/", "www.wrox.com");
//设置安全的 cookie
CookieUtil.set("name", "Nicholas", null, null, null, true); 

4. 子 cookie

子 cookie 最常见的的格式如下所示

name=name1=value1&name2=value2&name3=value3&name4=value4&name5=value5 

cookie 一般也以查询字符串的格式进行格式化。然后这些值可以使用单个 cookie 进行存储和访 问,而非对每个名称值对儿使用不同的 cookie 存储。最后网站或者 Web 应用程序可以无需达到单域名 cookie 上限也可以存储更加结构化的数据。

为了更好地操作子 cookie,必须建立一系列新方法。子 cookie 的解析和序列化会因子 cookie 的期望 用途而略有不同并更加复杂些。例如,要获得一个子 cookie,首先要遵循与获得 cookie 一样的基本步骤, 但是在解码 cookie 值之前,需要按如下方法找出子 cookie 的信息

var SubCookieUtil = {
 get: function (name, subName){
 var subCookies = this.getAll(name);
 if (subCookies){
 return subCookies[subName];
 } else {
 return null;
 }
 },
 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;
 }
 cookieValue = document.cookie.substring(cookieStart + cookieName.length, cookieEnd);
 if (cookieValue.length > 0){
 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;
 },
 //省略了更多代码
}; 

获取子 cookie 的方法有两个:get()和 getAll()。其中 get()获取单个子 cookie 的值,getAll() 获取所有子 cookie 并将它们放入一个对象中返回,对象的属性为子 cookie 的名称,对应值为子 cookie 对应的值。get()方法接收两个参数:cookie 的名字和子 cookie 的名字。它其实就是调用 getAll()获 取所有的子 cookie,然后只返回所需的那一个(如果 cookie 不存在则返回 null)。

SubCookieUtil.getAll()方法和 CookieUtil.get()在解析 cookie 值的方式上非常相似。区别 在于 cookie 的值并非立即解码,而是先根据&字符将子 cookie 分割出来放在一个数组中,每一个子 cookie 再根据等于号分割,这样在 parts 数组中的前一部分便是子 cookie 名,后一部分则是子 cookie 的值。 这两个项目都要使用 decodeURIComponent()来解码,然后放入 result 对象中,最后作为方法的返 回值。如果 cookie 不存在,则返回 null

可以像下面这样使用上述方法:

//假设 document.cookie=data=name=Nicholas&book=Professional%20JavaScript
//取得全部子 cookie
var data = SubCookieUtil.getAll("data");
alert(data.name); //"Nicholas"
alert(data.book); //"Professional JavaScript"
//逐个获取子 cookie
alert(SubCookieUtil.get("data", "name")); //"Nicholas"
alert(SubCookieUtil.get("data", "book")); //"Professional JavaScript" 

要设置子 cookie,也有两种方法:set()和 setAll()。以下代码展示了它们的构造。

var SubCookieUtil = {
 set: function (name, subName, value, expires, path, domain, secure) {
 var subcookies = this.getAll(name) || {}; 
subcookies[subName] = value;
 this.setAll(name, subcookies, expires, path, domain, secure);
 },
 setAll: function(name, subcookies, expires, path, domain, secure){
 var cookieText = encodeURIComponent(name) + "=",
 subcookieParts = new Array(),
 subName;
 for (subName in subcookies){
 if (subName.length > 0 && subcookies.hasOwnProperty(subName)){
 subcookieParts.push(encodeURIComponent(subName) + "=" +
 encodeURIComponent(subcookies[subName]));
 }
 }
 if (cookieParts.length > 0){
 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();
 }
 document.cookie = cookieText;
 },
 //省略了更多代码
}; 

这里的 set()方法接收 7 个参数:cookie 名称、子 cookie 名称、子 cookie 值、可选的 cookie 失效 日期或时间的 Date 对象、可选的 cookie 路径、可选的 cookie 域和可选的布尔 secure 标志。所有的可 选参数都是作用于cookie本身而非子cookie。为了在同一个cookie中存储多个子cookie,路径、域和secure 标志必须一致;针对整个 cookie 的失效日期则可以在任何一个单独的子 cookie 写入的时候同时设置。在 这个方法中,第一步是获取指定 cookie 名称对应的所有子 cookie。逻辑或操作符“||”用于当 getAll()返回 null 时将 subcookies 设置为一个新对象。然后,在 subcookies 对象上设置好子 cookie 值并传给 setAll()。

而 setAll()方法接收 6 个参数:cookie 名称、包含所有子 cookie 的对象以及和 set()中一样的 4 个可选参数。这个方法使用 for-in 循环遍历第二个参数中的属性。为了确保确实是要保存的数据,使 用了 hasOwnProperty()方法,来确保只有实例属性被序列化到子 cookie 中。由于可能会存在属性名 为空字符串的情况,所以在把属性名加入结果对象之前还要检查一下属性名的长度。将每个子 cookie 的名值对儿都存入 subcookieParts 数组中,以便稍后可以使用 join()方法以&号组合起来。剩下的 方法则和 CookieUtil.set()一样。 可以按如下方式使用这些方法。

//假设 document.cookie=data=name=Nicholas&book=Professional%20JavaScript
//设置两个 cookie
SubCookieUtil.set("data", "name", "Nicholas");
SubCookieUtil.set("data", "book", "Professional JavaScript");
//设置全部子 cookie 和失效日期
SubCookieUtil.setAll("data", { name: "Nicholas", book: "Professional JavaScript" },
 new Date("January 1, 2010"));
//修改名字的值,并修改 cookie 的失效日期
SubCookieUtil.set("data", "name", "Michael", new Date("February 1, 2010")); 

子 cookie 的最后一组方法是用于删除子 cookie 的。普通 cookie 可以通过将失效时间设置为过去的 时间的方法来删除,但是子 cookie 不能这样做。为了删除一个子 cookie,首先必须获取包含在某个 cookie 中的所有子 cookie,然后仅删除需要删除的那个子 cookie,然后再将余下的子 cookie 的值保存为 cookie 的值。请看以下代码。

var SubCookieUtil = {
 //这里省略了更多代码
 unset: function (name, subName, path, domain, secure){
 var subcookies = this.getAll(name);
 if (subcookies){
 delete subcookies[subName];
 this.setAll(name, subcookies, null, path, domain, secure);
 }
 },
 unsetAll: function(name, path, domain, secure){
 this.setAll(name, null, new Date(0), path, domain, secure);
 }
}; 

这里定义的两个方法用于两种不同的目的。unset()方法用于删除某个 cookie 中的单个子 cookie 而不影响其他的;而 unsetAll()方法则等同于 CookieUtil.unset(),用于删除整个 cookie。和 set()及 setAll()一样,路径、域和 secure 标志必须和之前创建的 cookie 包含的内容一致。这两个方法可 以像下面这样使用。

//仅删除名为 name 的子 cookie
SubCookieUtil.unset("data", "name");
//删除整个 cookie
SubCookieUtil.unsetAll("data"); 

3.2 IE用户数据

在 IE5.0 中,微软通过一个自定义行为引入了持久化用户数据的概念。用户数据允许每个文档最多 128KB 数据,每个域名最多 1MB 数据。要使用持久化用户数据,首先必须如下所示,使用 CSS 在某个 元素上指定 userData 行为:

<div style="behavior:url(#default#userData)" id="dataStore"></div> 

一旦该元素使用了 userData 行为,那么就可以使用 setAttribute()方法在上面保存数据了。 为了将数据提交到浏览器缓存中,还必须调用 save()方法并告诉它要保存到的数据空间的名字。数据 空间名字可以完全任意,仅用于区分不同的数据集。请看以下例子。

var dataStore = document.getElementById("dataStore");
dataStore.setAttribute("name", "Nicholas");
dataStore.setAttribute("book", "Professional JavaScript");
dataStore.save("BookInfo"); 

在这段代码中,<div>元素上存入了两部分信息。在用 setAttribute()存储了数据之后,调用了
save()方法,指定了数据空间的名称为 BookInfo。下一次页面载入之后,可以使用 load()方法指定
同样的数据空间名称来获取数据,如下所示。

dataStore.load("BookInfo"); 
alert(dataStore.getAttribute("name")); //"Nicholas"
alert(dataStore.getAttribute("book")); //"Professional JavaScript" 

对 load()的调用获取了 BookInfo 数据空间中的所有信息,并且使数据可以通过元素访问;只有 到载入确切完成之后数据方能使用。如果 getAttribute()调用了不存在的名称或者是尚未载入的名 程,则返回 null。 你可以通过 removeAttribute()方法明确指定要删除某元素数据,只要指定属性名称。删除之后, 必须像下面这样再次调用 save()来提交更改。

dataStore.removeAttribute("name");
dataStore.removeAttribute("book");
dataStore.save("BookInfo"); 

3.3 Web存储机制

Web Storage 最早是在 Web 超文本应用技术工作组(WHAT-WG)的 Web 应用 1.0 规范中描述的。 这个规范的最初的工作最终成为了 HTML5 的一部分。Web Storage 的目的是克服由 cookie 带来的一些限 制,当数据需要被严格控制在客户端上时,无须持续地将数据发回服务器。Web Storage 的两个主要目 标是:

 提供一种在 cookie 之外存储会话数据的途径;

 提供一种存储大量可以跨会话存在的数据的机制。

最初的 Web Storage 规范包含了两种对象的定义:sessionStorage 和 globalStorage。这两个 对象在支持的浏览器中都是以 windows 对象属性的形式存在的,支持这两个属性的浏览器包括 IE8+、 Firefox 3.5+、Chrome 4+和 Opera 10.5+。

1. Storage 类型

Storage 类型提供最大的存储空间(因浏览器而异)来存储名值对儿。Storage 的实例与其他对 象类似,有如下方法。

 clear(): 删除所有值;Firefox 中没有实现 。

 getItem(name):根据指定的名字 name 获取对应的值。

 key(index):获得 index 位置处的值的名字。

 removeItem(name):删除由 name 指定的名值对儿。

 setItem(name, value):为指定的 name 设置一个对应的值

其中,getItem()、removeItem()和 setItem()方法可以直接调用,也可通过 Storage 对象间 接调用。因为每个项目都是作为属性存储在该对象上的,所以可以通过点语法或者方括号语法访问属性 来读取值,设置也一样,或者通过 delete 操作符进行删除。不过,我们还建议读者使用方法而不是属 性来访问数据,以免某个键会意外重写该对象上已经存在的成员

还可以使用 length 属性来判断有多少名值对儿存放在 Storage 对象中。但无法判断对象中所有 数据的大小,不过 IE8 提供了一个 remainingSpace 属性,用于获取还可以使用的存储空间的字节数。

Storage 类型只能存储字符串。非字符串的数据在存储之前会被转换成字符串。

2. sessionStorage 对象

sessionStorage 对象存储特定于某个会话的数据,也就是该数据只保持到浏览器关闭。这个对象 就像会话 cookie,也会在浏览器关闭后消失。存储在 sessionStorage 中的数据可以跨越页面刷新而 存在,同时如果浏览器支持,浏览器崩溃并重启之后依然可用(Firefox 和 WebKit 都支持,IE 则不行)。 因为 seesionStorage 对象绑定于某个服务器会话,所以当文件在本地运行的时候是不可用的。存 储在 sessionStorage 中的数据只能由最初给对象存储数据的页面访问到,所以对多页面应用有限制。 由于 sessionStorage 对象其实是 Storage 的一个实例,所以可以使用 setItem()或者直接设 置新的属性来存储数据。下面是这两种方法的例子。

//使用方法存储数据
sessionStorage.setItem("name", "Nicholas");
//使用属性存储数据
sessionStorage.book = "Professional JavaScript"; 

在 IE8 中可以强制把数据写入磁盘:在设置新数据之前使用 begin()方法,并且在所有设置完成之 后调用 commit()方法。看以下例子。

//只适用于 IE8
sessionStorage.begin();
sessionStorage.name = "Nicholas";
sessionStorage.book = "Professional JavaScript";
sessionStorage.commit();

sessionStorage 中有数据时,可以使用 getItem()或者通过直接访问属性名来获取数据。两种 方法的例子如下。

//使用方法读取数据
var name = sessionStorage.getItem("name");
//使用属性读取数据
var book = sessionStorage.book; 

还可以通过结合 length 属性和 key()方法来迭代 sessionStorage 中的值,如下所示。

for (var i=0, len = sessionStorage.length; i < len; i++){
 var key = sessionStorage.key(i);
 var value = sessionStorage.getItem(key);
 alert(key + "=" + value);
} 

它是这样遍历 sessionStorage 中的名值对儿的:首先通过 key()方法获取指定位置上的名字, 然后再通过 getItem()找出对应该名字的值。 还可以使用 for-in 循环来迭代 sessionStorage 中的值:

for (var key in sessionStorage){
 var value = sessionStorage.getItem(key);
 alert(key + "=" + value);
} 

要从 sessionStorage 中删除数据,可以使用 delete 操作符删除对象属性,也可调用 removeItem()方法。以下是这些方法的例子。

//使用 delete 删除一个值——在 WebKit 中无效
delete sessionStorage.name;
//使用方法删除一个值
sessionStorage.removeItem("book"); 

3. globalStorage 对象

Firefox 2 中实现了 globalStorage 对象。作为最初的 Web Storage 规范的一部分,这个对象的目 的是跨越会话存储数据,但有特定的访问限制。要使用 globalStorage,首先要指定哪些域可以访问该数据。可以通过方括号标记使用属性来实现,如以下例子所示。

//保存数据
globalStorage["wrox.com"].name = "Nicholas";
//获取数据
var name = globalStorage["wrox.com"].name; 

在这里,访问的是针对域名 wrox.com 的存储空间。globalStorage 对象不是 Storage 的实例, 而具体的 globalStorage["wrox.com"]才是。这个存储空间对于 wrox.com 及其所有子域都是可以 访问的。可以像下面这样指定子域名。

//保存数据
globalStorage["www.wrox.com"].name = "Nicholas";
//获取数据
var name = globalStorage["www.wrox.com"].name; 

对 globalStorage 空间的访问,是依据发起请求的页面的域名、协议和端口来限制的。例如,如 果使用 HTTPS 协议在 wrox.com 中存储了数据,那么通过 HTTP 访问的 wrox.com 的页面就不能访问 该数据。同样,通过 80 端口访问的页面则无法与同一个域同样协议但通过 8080 端口访问的页面共享数 据。这类似于 Ajax 请求的同源策略。 globalStorage 的每个属性都是 Storage 的实例。因此,可以像如下代码中这样使用。

globalStorage["www.wrox.com"].name = "Nicholas";
globalStorage["www.wrox.com"].book = "Professional JavaScript";
globalStorage["www.wrox.com"].removeItem("name");
var book = globalStorage["www.wrox.com"].getItem("book"); 

4. localStorage 对象

ocalStorage 对象在修订过的 HTML 5 规范中作为持久保存客户端数据的方案取代了 globalStorage。与 globalStorage 不同,不能给 localStorage 指定任何访问规则;规则事先就 设定好了。要访问同一个 localStorage 对象,页面必须来自同一个域名(子域名无效),使用同一种 协议,在同一个端口上。这相当于 globalStorage[location.host]。 由于 localStorage 是 Storage 的实例,所以可以像使用 sessionStorage 一样来使用它。下 面是一些例子。

//使用方法存储数据
localStorage.setItem("name", "Nicholas");
//使用属性存储数据
localStorage.book = "Professional JavaScript";
//使用方法读取数据
var name = localStorage.getItem("name");
//使用属性读取数据
var book = localStorage.book; 

存储在 localStorage 中的数据和存储在 globalStorage 中的数据一样,都遵循相同的规则: 数据保留到通过 JavaScript 删除或者是用户清除浏览器缓存。 为了兼容只支持 globalStorage 的浏览器,可以使用以下函数

function getLocalStorage(){
 if (typeof localStorage == "object"){
 return localStorage;
 } else if (typeof globalStorage == "object"){
 return globalStorage[location.host];
 } else {
 throw new Error("Local storage not available.");
 }
} 

然后,像下面这样调用一次这个函数,就可以正常地读写数据了。

var storage = getLocalStorage(); 

5. storage 事件

以下代码展示了如何侦听 storage 事件:

EventUtil.addHandler(document, "storage", function(event){
 alert("Storage changed for " + event.domain);
}); 

3.4 IndexedDB

本节示例中将使用 IndexedDB, 而实际上每个示例前面都应该加上下面这行代码:

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

1. 数据库

使用 IndexedDB 的第一步是打开它,即把要打开的数据库名传给 indexDB.open()。如果传入的 数据库已经存在,就会发送一个打开它的请求;如果传入的数据库还不存在,就会发送一个创建并打开 它的请求。总之,调用indexDB.open()会返回一个IDBRequest 对象,在这个对象上可以添加onerror 和 onsuccess 事件处理程序。先来看一个例子。

var indexedDB = window.indexedDB || window.msIndexedDB || window.mozIndexedDB ||
window.webkitIndexedDB; 
var request, database;
request = indexedDB.open("admin");
request.onerror = function(event){
 alert("Something bad happened while trying to open: " +
 event.target.errorCode);
};
request.onsuccess = function(event){
 database = event.target.result;
}; 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值