一、离线应用
离线 Web 应用:在设备不能上网的情况下仍然可以运行的应用。(HTML5 一个重点)
开发离线 Web 应用的几个步骤:
1)确保应用知道设备是否能上网,以便下一步执行正确的操作。
2)应用必须能访问一定的资源(图像、JavaScript、CSS 等),只有这样才能正常工作。
3)必须有一块本地空间用于保存数据,无论能否上网都不妨碍读写。
1. 离线检测
navigator.onLine 属性:判断设备是在线还是离线,true 表示设备能上网,false 表示设备离线。(有浏览器兼容问题)
为了更好地确定网络是否可用,HTML5 还定义了两个事件:online 和 offline。
当网络从离线变为在线或者从在线变为离线时,分别触发这两个事件。这两个事件在 window 对象上触发。
检测应用是否离线:在页面加载后,最好先通过 navigator.onLine 取得初始的状态。然后,通过上述两个事件来确定网络连接状态是否变化。
当上述事件触发时, navigator.onLine 属性的值也会改变,不过必须要手工轮询这个属性才能检测到网络状态的变化。
支持离线检测的浏览器:IE 6+(只支持 navigator.onLine 属性)、Firefox 3、Safari 4、Opera 10.6、Chrome、iOS 3.2 版 Safari和 Android 版 WebKit。
2. 应用缓存
应用缓存(application cache,简称appcache):专门为开发离线 Web 应用而设计的,Appcache 就是从浏览器的缓存中分出来的一块缓存区。
要想在这个缓存中保存数据,可以使用一个描述文件(manifest file),列出要下载和缓存的资源。
简单的描述文件示例:
CACHE MANIFEST
#Comment
file.js
file.css
将描述文件与页面关联起来,可以在 <html> 中的 manifest 属性中指定这个文件的路径。
<html manifest="/offline.manifest">
applicationCache 对象:
属性:
status:属性的值是常量,表示应用缓存的当前状态。0-无缓存,1-闲置,2-检查中,3-下载中,4-更新完成,可使用swapCache(),5-废弃。
应用缓存事件:
checking:在浏览器为应用缓存查找更新时触发。
error:在检查更新或下载资源期间发生错误时触发。
noupdate:在检查描述文件发现文件无变化时触发。
downloading:在开始下载应用缓存资源时触发。
progress:在文件下载应用缓存的过程中持续不断地触发。
updateready:在页面新的应用缓存下载完毕且可以通过 swapCache() 使用时触发。
cached:在应用缓存完整可用时触发。
一般来讲,这些事件会随着页面加载按上述顺序依次触发。
通过调用 update() 方法可以手工干预,让应用缓存为检查更新而触发上述事件。(就像页面刚刚加载一样)
applicationCache.update();
如果触发了 updateready 事件,说明新版本的应用缓存已经可用,此时需要调用 swapCache() 来启用新应用缓存。
EventUtil.addHandler(applicationCache, "updateready", function(){
applicationCache.swapCache();
});
支持 HTML5 应用缓存的浏览器:Firefox 3+、Safari 4+、Opera 10.6、Chrome、iOS 3.2+版 Safari 及 Android 版 WebKit。
3. 数据存储
(1) Cookie ☆
HTTP Cookie(通常直接叫cookie),最初是在客户端用于存储会话信息的。
该标准要求服务器对任意 HTTP 请求发送 Set-Cookie HTTP 头作为响应的一部分,其中包含会话信息。浏览器会存储这样的会话信息,并在这之后,通过为每个请求添加 Cookie HTTP 头将信息发送回服务器。
// 服务器响应头
HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value
Other-header: other-header-value
// 浏览器请求头
GET /index.html HTTP/1.1
Cookie: name=value
Other-header: other-header-value
1.限制
1)每个域的 cookie 总数是有限的,浏览器之间各有不同。当超过单个域名限制之后还要再设置 cookie,浏览器就会清除以前设置的 cookie。
2)cookie 尺寸有限制,最好将整个 cookie 长度限制在 4095B(含 4095)以内。
2.cookie 的构成
名称:一个唯一确定 cookie 的名称。必须被 URL 编码。
值:储存在 cookie 中的字符串值。必须被 URL 编码。
域:cookie 对于哪个域是有效的。所有向该域发送的请求中都会包含这个 cookie 信息。如果没有明确设定,这个域会被认作来自设置 cookie 的那个域。
路径:对于指定域中的那个路径,应该向服务器发送 cookie。
失效时间:表示 cookie 何时应该被删除的时间戳。默认情况下,浏览器会话结束时即将所有 cookie 删除;不过也可以自己设置删除时间。如果设置的失效日期是以前时间,cookie 会被立刻删除。
安全标志:指定后,cookie 只有在使用 SSL 连接的时候才发送到服务器。
使用:Set-Cookie: name=value; expires=Mon, 22-Jan-07 07:10:24 GMT; domain=.wrox.com; path=/; secure
每一段信息作为 Set-Cookie 头的一部分,使用分号加空格分隔,secure 标志是 cookie 中唯一一个非名值对儿的部分,直接包含一个 secure 单词。
注意:域、路径、失效时间和 secure 标志都是服务器给浏览器的指示,以指定何时应该发送 cookie。这些参数不会作为发送到服务器的 cookie 信息的一部分,只有名值对儿才会被发送。
3.JavaScript 中的 cookie
document. cookie 属性:获取属性值时返回当前页面可用的所有 cookie 的字符串;设置值时可以设置为一个新的 cookie 字符串,解释并添加到现有的 cookie 集合中。(只有名和值必需)
document.cookie = encodeURIComponent("name") + "=" + encodeURIComponent("Nicholas") + "; domain=.wrox.com; path=/";
基本的 cookie 操作有三种:【读取】、【写入】和【删除】。
没有删除直接方法,使用相同的路径、域和安全选项再次设置 cookie,并将失效时间设置为过去的时间。
4.子 cookie
子cookie(subcookie):存放在单个 cookie 中的更小段的数据。也就是使用 cookie 值来存储多个名称值对儿。
常见格式:
name=name1=value1&name2=value2&name3=value3&name4=value4&name5=value5
注意:使用单个 cookie 进行存储和访问,而非对每个名值对儿使用不同的 cookie 存储。
【获取】:get() 获取单个子 cookie 的值,getAll() 获取所有子 cookie 并将它们放入一个对象中。
【设置】:除名值外的可选参数都是作用于 cookie 本身而非子 cookie。为了在同一个 cookie 中存储多个子 cookie,路径、域和 secure 标志必须一致;针对整个 cookie 的失效日期可以在任何一个单独的子 cookie 写入的时候同时设置。
【删除】:删除一个子 cookie,首先必须获取包含在某个 cookie 中的所有子 cookie,然后仅删除需要删除的那个子 cookie,再将余下的子 cookie 的值保存为 cookie 的值。
(2) IE用户数据
在 IE5.0 中,微软通过一个自定义行为引入了持久化用户数据的概念。用户数据允许每个文档最多 128KB 数据,每个域名最多 1MB 数据。、
使用持久化用户数据,首先使用 CSS 在某个元素上指定 userData 行为:
<div style="behavior:url(#default#userData)" id="dataStore"></div>
一旦该元素使用了 userData 行为,就可以使用 setAttribute() 方法在上面保存数据。
为了将数据提交到浏览器缓存中,还必须调用 save() 方法并告诉它要保存到的数据空间的名字。
下一次页面载入之后,可以使用 load() 方法指定同样的数据空间名称来获取数据。
使用 removeAttribute() 方法明确指定要删除某元素数据,只要指定属性名称。删除之后,必须再次调用 save() 来提交更改。
// 保存数据
var dataStore = document.getElementById("dataStore");
dataStore.setAttribute("name", "Nicholas");
dataStore.setAttribute("book", "Professional JavaScript");
dataStore.save("BookInfo");
// 获取数据
dataStore.load("BookInfo");
alert(dataStore.getAttribute("name")); //"Nicholas"
alert(dataStore.getAttribute("book")); //"Professional JavaScript"
// 删除数据
dataStore.removeAttribute("name");
dataStore.removeAttribute("book");
dataStore.save("BookInfo");
对 IE 用户数据的访问限制和对 cookie 的限制比较:
类似点:要访问某个数据空间,脚本运行的页面必须来自同一个域名,在同一个路径下,并使用与进行存储的脚本同样的协议。IE 用户数据并非安全的,不能存放敏感信息。
不同点:和 cookie 不同,无法将用户数据访问限制扩展到更多的客户。用户数据默认是可以跨越会话持久存在的,同时也不会过期;数据需要通过 removeAttribute() 方法专门进行删除以释放空间。
(3) Web存储机制 ☆
Web Storage 的两个主要目标:
提供一种在 cookie 之外存储会话数据的途径;
提供一种存储大量可以跨会话存在的数据的机制。
最初的 Web Storage 规范包含了两种对象的定义: sessionStorage 和 globalStorage 。这两个对象在支持的浏览器中都是以 windows 对象属性的形式存在的。
支持浏览器:IE8+、Firefox 3.5+、Chrome 4+ 和 Opera 10.5+。
1.Storage 类型
clear():删除所有值;Firefox 中没有实现。
getItem(name):根据指定的名字 name 获取对应的值。
key(index):获得 index 位置处的值的名字。
removeItem(name):删除由 name 指定的名值对儿。
setItem(name, value):为指定的 name 设置一个对应的值。
length属性:判断有多少名值对儿存放在 Storage 对象中。
IE8 提供了一个 remainingSpace 属性,用于获取还可以使用的存储空间的字节数。
Storage 类型只能存储字符串。非字符串的数据在存储之前会被转换成字符串。
2.sessionStorage 对象
sessionStorage 对象存储特定于某个会话的数据,该数据只保持到浏览器关闭。可以跨越页面刷新而存在。
因为 seesionStorage 对象绑定于某个服务器会话,所以当文件在本地运行的时候是不可用的。存储在 sessionStorage 中的数据只能由最初给对象存储数据的页面访问到,所以对多页面应用有限制。
sessionStorage 对象是 Storage 的一个实例。
存储数据:setItem() 或者直接设置新属性
//使用方法存储数据
sessionStorage.setItem("name", "Nicholas");
//使用属性存储数据
sessionStorage.book = "Professional JavaScript";
获取数据:getItem() 或者直接访问属性名
//使用方法读取数据
var name = sessionStorage.getItem("name");
//使用属性读取数据
var book = sessionStorage.book;
迭代 sessionStorage 中的值:
// 结合 length 属性和 key() 方法
for (var i=0, len = sessionStorage.length; i < len; i++){
var key = sessionStorage.key(i);
var value = sessionStorage.getItem(key);
alert(key + "=" + value);
}
// for-in 循环
for (var key in sessionStorage){
var value = sessionStorage.getItem(key);
alert(key + "=" + value);
}
删除数据:delete 操作符或者 removeItem() 方法
//使用 delete 删除一个值——在 WebKit 中无效
delete sessionStorage.name;
//使用方法删除一个值
sessionStorage.removeItem("book");
sessionStorage 对象应该主要用于仅针对会话的小段数据的存储。
3.globalStorage 对象
跨越会话存储数据,但有特定的访问限制,首先要指定哪些域可以访问该数据。
//保存数据
globalStorage["wrox.com"].name = "Nicholas";
//获取数据
var name = globalStorage["wrox.com"].name;
//存储数据,任何人都可以访问——不要这样做!
globalStorage[""].name = "Nicholas";
//存储数据,可以让任何以.net 结尾的域名访问——不要这样做!
globalStorage["net"].name = "Nicholas";
globalStorage 对象不是 Storage 的实例,而具体的 globalStorage[“wrox.com”] 才是。
globalStorage 的每个属性都是 Storage 的实例。
事先不能确定域名,使用 location.host 作为属性名比较安全。
globalStorage[location.host].name = "Nicholas";
var book = globalStorage[location.host].getItem("book");
如果不使用 removeItem() 或者 delete 删除,或者用户未清除浏览器缓存,存储在 globalStorage 属性中的数据会一直保留在磁盘上。
globalStorage 非常适合在客户端存储文档或者长期保存用户偏好设置。
4.localStorage 对象
localStorage 对象取代了 globalStorage,作为持久保存客户端数据的方案。
与 globalStorage 不同,不能给 localStorage 指定任何访问规则。
要访问同一个 localStorage 对象,页面必须来自同一个域名(子域名无效),使用同一种协议,在同一个端口上。相当于 globalStorage[location.host]。
localStorage 是 Storage 的实例。
//使用方法存储数据
localStorage.setItem("name", "Nicholas");
//使用属性存储数据
localStorage.book = "Professional JavaScript";
//使用方法读取数据
var name = localStorage.getItem("name");
//使用属性读取数据
var book = localStorage.book;
数据保留到通过 JavaScript 删除或者是用户清除浏览器缓存。
5.storage 事件
对 Storage 对象进行任何修改,都会在文档上触发 storage 事件。
event 对象属性:
domain:发生变化的存储空间的域名。
key:设置或者删除的键名。
newValue:如果是设置值,则是新值;如果是删除键,则是 null。
oldValue:键被更改之前的值。
EventUtil.addHandler(document, "storage", function(event){
alert("Storage changed for " + event.domain);
});
6.限制
localStorage大多数浏览器设置每个来源(协议、域和端口) 5MB 的限制,最小 2.5MB。
sessionStorage因浏览器而异,最小的限制 2.5MB。
(4) IndexedDB
Indexed Database API,简称 IndexedDB,是在浏览器中保存结构化数据的一种数据库。
var indexedDB = window.indexedDB || window.msIndexedDB || window.mozIndexedDB || window.webkitIndexedDB;
IndexedDB是一个数据库,最大的特色是使用对象保存数据,而不是使用表来保存数据。
IndexedDB是一种类似 SQL 数据库的结构化数据存储机制。
创建对象存储空间时,需要定义一个键,然后就可以添加数据。
可以使用游标在对象存储空间中查询特定的对象。
索引是为了提高查询速度而基于特定的属性创建的。
对 IndexedDB 的限制很多都与对 Web Storage 的类似。
IndexedDB 数据库只能由同源(相同协议、域名和端口)页面操作,不能跨域共享信息。
每个来源的数据库占用的磁盘空间也有限制。
Firefox 还有另外一个限制,不允许本地文件访问 IndexedDB。
上一篇:48-JavaScript高级程序设计-高级技巧3自定义事件&拖放
下一篇:50-JavaScript高级程序设计-最佳实践1可维护性