离线应用与客户端存储
离线Web应用,就是在设备不能上网的情况下仍然可以运行的应用。开发离线Web应用的步骤:首先确保应用知道设备是否能上网,然后应用还必须能访问一定的资源(图像,JavaScript,CSS等),只有这样才能正常工作。最后必须有一块本地空间用于保存数据。
1.离线检测
HTML5定义了一个navigator.onLine属性,true表示能上网,false表示离线。同时还定义了online和offline事件,在window对象上触发。在页面加载后,最好先通过navigator.onLine取得初始的状态。然后通过上述两个事件来确定网络连接状态是否变化。var div = document.getElementById("editDiv"); div.addEventListener("click",function(){ if(navigator.onLine){ console.log("在线"); }else{ console.log("离线"); } },false); window.addEventListener("online",function(){ console.log("上线"); },false); window.addEventListener("offline",function(){ console.log("下线"); },false);
2.应用缓存
HTML5的应用缓存(application cache)是专门为Web离线应用设计的。即从浏览器的缓存中分出来的一块缓存区。使用描述文件(manifest file),列出要下载和缓存的资源。如:CACHE MANIFEST #Comment flag.png test.js
3.数据存储
1.Cookie
服务器端通过响应消息头在客户端设置cookie,如:
浏览器存储cookie后,通过给每个请求添加Cookie HTTP 头消息,将cookie信息发送回服务器,如:HTTP/1.1 200 OK Content-type:text/html Set-Cookie:name=value
GET /index.html HTTP/1.1 Cookie:name=value
1.限制
每个域名最多20个cookie(不同浏览器有所不同);
每个cookie最大4kB
2.cookie构成
name:必须,不区分大小写(myCookie和MyCookie是一个,名字重复就覆盖了),需要经过URL编码
value:必须,需要经过URL编码
domain:(可选) 域名,默认cookie所属网站的域名(所有向该域发送的请求中都会带cookie信息)
path:(可选) 指定域中的某个路径(向该路径下的请求发送cookie)
maxage:(可选)最大存活时间,默认会话结束cookie删除。可自己设置GMT格式的日期(Wdy,DD-Mon-YYYY HH:MM:SS GMT)
secure:(可选)指定后,cookie只有在使用SSL连接时才发送到服务器。https请求
唯一确定一个Cookie:domain+path+name
3.JS中的cookie
通过BOM的document.cookie属性来操作cookie。用来获取cookie:返回当前页面可用的所有cookie的字符串,name1=value1;name2=value2;name3=value3设置cookie:cookie字符串会被解释并添加到现有的cookie集合中。设置document.cookie不会覆盖cookie,除非设置的cookie名称已经存在document.cookie = encodeURIComponent("name")+"="+encodeURIComponent("zhangsan")+";domain=www.xxx.com;path=/";
JS自定义cookie操作工具: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,expire,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); } };
4.子cookie
为了绕开浏览器的单域名下的cookie数限制,在cookie值中存放多个键值对,格式如下:
subcookie使用解析对象:name=name1=value1&name2=value2&name3=value3
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(var i=0,len=subCookies.length;i<len;i++){ parts = subCookies[i].split("="); result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]); } return result; } } return null; } };
subcookie工具设置cookie值:
删除子cookie值://设置单个键值对信息 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){//遍历name值对象的属性 if(subName.length>0 && subcookies.hasOwnProperty(subName)){//确保只有实例属性被序列化到子cookie中 subcookieParts.push(encodeURIComponent(subName)+"="+encodeURIComponent(subcookies[subName])); } } if(subcookieParts.length>0){//键值对数组拼接成字符串 cookieText +=subcookieParts.join("&"); //拼接其他cookie属性值 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; }
//删除子cookie unset:function(name,subName,path,domain,secure){ var subcookies = this.getAll(name); if(subcookies){ delete subcookies[subName];//删除数组中指定值,数组长度不变,值改为undefined this.setAll(name,subcookies,null,path,domain,secure); } }, //删除整个cookie unsetAll:function(name,path,domain,secure){ this.setAll(name,null,new Date(0),path,domain,secure); }
由于cookie都会由浏览器作为请求头发送,所以在cookie中存储大量信息会影响到特定域的请求性能。cookie信息越大,完成对服务器请求的时间也就越长。所以尽可能在cookie中少存储信息,避免影响想能。
2.Web存储机制
Web Storage的目的是客服由cookie带来的一些限制
- 提供一种在cookie之外存储会话数据的途径;
- 提供一种存储大量可以跨会话存在的数据的机制。
最初的Web Storage规范包含了两种对象的定义:sessionStorage和globalStorage。这两个对象在支持的浏览器中都是以windows对象属性的形式存在的。1.Storage类型
提供最大的存储空间(因浏览器而异)来存储名值对。提供方法如下:
- clear():删除所有值
- getItem(name):根据指定的名字name获取对应的值
- key(index):获得index位置处的值的名字
- removeItem(name):删除由name指定的名值对
- setItem(name,value):为指定的name设置一个对应的值
storage类型只能存储字符串,非字符串的数据在存储前会被转成字符串
2.sessionStorage对象
存储某个特定会话的数据,该数据保持到浏览器关闭。存储在sessionStorage中的数据可以跨越页面刷新而存在。
因为sessionStorage对象绑定于某个服务器会话,所以当文本在本地运行的时候是不可用的。存储在sessionStorage中的数据只能由最初给对象存储数据的页面访问到,所以对多页面应用有限制。
//使用方法设置数据 sessionStorage.setItem("name","zhangsan"); //使用属性设置数据 sessionStorage.book = "math"; console.log(sessionStorage);//Storage {book: "math", name: "zhangsan", length: 2}
使用getItem或属性的方式访问数据:var name =sessionStorage.getItem("name"); var book = sessionStorage.book;
遍历获取sessionStorage中的名值对:for(var i =0,len=sessionStorage.length;i<len;i++){ var key = sessionStorage.key(i); var value = sessionStorage.getItem(key); console.log(key+"="+value); } for(var key in sessionStorage){//不会返回内置方法或length属性 value = sessionStorage.getItem(key); console.log(key+"="+value); }
delete删除属性或removeItem()方法删除数据:delete sessionStorage.name; sessionStorage.removeItem("book");
3.localStorage对象
存储数据的规则是固定的。要访问同一个globalStorage对象,页面必须来自同一个域名(子域名无效),使用同一种协议,在同一个端口上。
localStorage也是Storage的实例,所以可以像使用sessionStorage一样来使用它。
localStorage.setItem("name","zhangsan"); localStorage.book = "math"; var name = localStorage.name; var book = localStorage.getItem("book");
数据保留到通过JavaScript删除或者是用户清除浏览器缓存。
4.storage事件
对Storage对象进行任何修改,都会在文档上触发storage事件。
- 通过属性或setItem()方法保存数据
- 使用delete操作符或removeItem()删除数据
- 调用clear()方法
event对象有一下属性:
- domain:发生变化的存储空间的域名。
- key:设置或删除的键名
- newValue:如果是设置值,则是新值;如果是删除键,则是null
- oldValue:键被更改之前的值
//chrome不支持? window.addEventListener("storage",function(event){ console.log(event); },false); localStorage.setItem("name","zhangsan");
5.限制
对存储空间大小的限制都是以每个来源(协议,域,端口)为单位的。每个源都有固定大小的空间用于保存自己的数据。
localStorage:5MB大小限制,chrome限制2.5MB
sessionStorage:2.5MB