HTML5 LocalStorage,sessionStorage 本地存储

转载 (原文地址) pingfan 随笔 js 3027阅读 2014-08-20 22:10:12 举报

HTML5 LocalStorage 本地存储

说到本地存储,这玩意真是历尽千辛万苦才走到HTML5这一步,之前的历史大概如下图所示:

最早的Cookies自然是大家都知道,问题主要就是太小,大概也就4KB的样子,而且IE6只支持每个域名20个cookies,太少了。优势就是大家都支持,而且支持得还蛮好。很早以前那些禁用cookies的用户也都慢慢的不存在了,就好像以前禁用javascript的用户不存在了一样。

userData是IE的东西,垃圾。现在用的最多的是Flash吧,空间是Cookie的25倍,基本够用。再之后Google推出了Gears,虽然没有限制,但不爽的地方就是要装额外的插件(没具体研究过)。到了HTML5把这些都统一了,官方建议是每个网站5MB,非常大了,就存些字符串,足够了。比较诡异的是居然所有支持的浏览器目前都采用的5MB,尽管有一些浏览器可以让用户设置,但对于网页制作者来说,目前的形势就5MB来考虑是比较妥当的。

HTML5LocalStorage,sessionStorage本地存储

支持的情况如上图,IE在8.0的时候就支持了,非常出人意料。不过需要注意的是,IE、Firefox测试的时候需要把文件上传到服务器上(或者localhost),直接点开本地的HTML文件,是不行的。

首先自然是检测浏览器是否支持本地存储。在HTML5中,本地存储是一个window的属性,包括localStorage和sessionStorage,从名字应该可以很清楚的辨认二者的区别,前者是一直存在本地的,后者只是伴随着session,窗口一旦关闭就没了。二者用法完全相同,这里以localStorage为例。

[code]
//检测浏览器是否支持本地存储
if(window.localStorage){
alert('This browser supports localStorage');
}else{
alert('This browser does NOT support localStorage');
}[/code]

存储数据的方法就是直接给window.localStorage添加一个属性,例如:window.localStorage.a 或者 window.localStorage["a"]。它的读取、写、删除操作方法很简单,是以键值对的方式存在的,如下:

[code]localStorage.a = 3;//设置a为"3"
localStorage["a"] = "sfsf";//设置a为"sfsf",覆盖上面的值
localStorage.setItem("b","isaac");//设置b为"isaac"
var a1 = localStorage["a"];//获取a的值
var a2 = localStorage.a;//获取a的值
var b = localStorage.getItem("b");//获取b的值
localStorage.removeItem("c");//清除c的值[/code]

这里最推荐使用的自然是getItem()和setItem(),清除键值对使用removeItem()。如果希望一次性清除所有的键值对,可以使用clear()。另外,HTML5还提供了一个key()方法,可以在不知道有哪些键值的时候使用,如下:

[code]var storage = window.localStorage;
function showStorage(){
for(var i=0;i<storage.length;i++){
//key(i)获得相应的键,再用getItem()方法获得对应的值
document.write(storage.key(i)+ " : " + storage.getItem(storage.key(i)) + "<br>");
}
}[/code]

写一个最简单的,利用本地存储的计数器:

HTML5LocalStorage,sessionStorage本地存储

代码片段 1

[code]<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>localstorage本地存储</title>
</head>
<body>
有多少人进来访问<span id="count"></span><br />
<span id="content"></span>
<script type="text/javascript">
if(window.localStorage){
var storage = window.localStorage;

    function showStorage(){
        for(var i=0;i<storage.length;i++){

            //key(i)获得相应的键,再用getItem()方法获得对应的值
            document.getElementById('content').innerHTML=storage.key(i) + " : " + storage.getItem(storage.key(i))+"<br />";
        } 
    }   

    //不存在本地存储pageLoadCount值时,设置为0,  ie7一下localstorage存储的是对象,ie8及以上存储的是字符串
    if (!storage.getItem("pageLoadCount")){
        storage.setItem("pageLoadCount",0);
    } 

    //window.localStorage存储的是字符串,要转换格式进行加减
    storage.pageLoadCount = parseInt(storage.getItem("pageLoadCount")) + 1;//必须格式转换

    document.getElementById("count").innerHTML = storage.pageLoadCount;

    showStorage();
}else{
    alert('您的浏览器不支持本地存储localStorage');
}   
</script>

</body>
</html>[/code]

需要注意的是,HTML5本地存储只能存字符串,任何格式存储的时候都会被自动转为字符串,所以读取的时候,需要自己进行类型的转换。这也就是上一段代码中parseInt必须要使用的原因。

另外,在iPhone/iPad上有时设置setItem()时会出现诡异的QUOTA_EXCEEDED_ERR错误,这时一般在setItem之前,先removeItem()就ok了。

HTML5的本地存储,还提供了一个storage事件,可以对键值对的改变进行监听,使用方法如下:

[code] if(window.addEventListener){
window.addEventListener("storage",handle_storage,false);
}else if(window.attachEvent){
window.attachEvent("onstorage",handle_storage);
}
function handle_storage(e){
if(!e){e=window.event;}
//showStorage();
}[/code]

对于事件变量e,是一个StorageEvent对象,提供了一些实用的属性,可以很好的观察键值对的变化,如下表:

HTML5LocalStorage,sessionStorage本地存储

这里添加两个键值对a和b,并增加一个按钮。给a设置固定的值,当点击按钮时,修改b的值:

[code]<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>HTML5 LocalStorage 本地存储</title>
</head>
<body>
<p>您浏览当前页面多少 <span id="count">0</span> 次</p>
<p><input type="button" value="changeStorage" onClick="changeS()"/></p>
<script>
if(window.localStorage){

    var storage = window.localStorage;

    if (!storage.getItem("pageLoadCount")) storage.setItem("pageLoadCount",0);

    //格式转换 进行想家
    storage.pageLoadCount = parseInt(storage.getItem("pageLoadCount")) + 1;
    document.getElementById("count").innerHTML = storage.pageLoadCount;
    showStorage();

    if(window.addEventListener){
     window.addEventListener("storage",handle_storage,false);
    }else if(window.attachEvent){
     window.attachEvent("onstorage",handle_storage);
    }

    function handle_storage(e){
     if(!e){e=window.event;}
     showObject(e);
    }

    function showObject(obj){

         //递归显示object
         if(!obj){return;}
         for(var i in obj){
          if(typeof(obj[i])!="object" || obj[i]==null){
           document.write(i + " : " + obj[i] + "<br/>");
          }else{
           document.write(i + " : object" + "<br/>");
          }
         }
    }

    //设置a为5
    storage.setItem("a",5);

    function changeS(){
         //修改一个键值,测试storage事件
         if(!storage.getItem("b")){storage.setItem("b",0);}
         storage.setItem('b',parseInt(storage.getItem('b'))+1);
    }

    function showStorage(){
         //循环显示localStorage里的键值对
         for(var i=0;i<storage.length;i++){
          //key(i)获得相应的键,再用getItem()方法获得对应的值
          document.write(storage.key(i)+ " : " + storage.getItem(storage.key(i)) + "<br>");
         }
    }
}
</script> 

</body>
</html>[/code]

测试发现,目前浏览器对这个支持不太好,仅iPad和Firefox支持,而且Firefox支持得乱糟糟,e对象根本没有那些属性。iPad支持非常好,用的是e.uri(不是e.url),台式机上的Safari不行,诡异。

目前浏览器都带有很好的开发者调试功能,下面分别是Chrome和Firefox的调试工具查看LocalStorage:

HTML5LocalStorage,sessionStorage本地存储

另外,目前javascript使用非常多的json格式,如果希望存储在本地,可以直接调用JSON.stringify()将其转为字符串。读取出来后调用JSON.parse()将字符串转为json格式,如下所示:

HTML5LocalStorage,sessionStorage本地存储

JSON对象在支持localStorage的浏览器上基本都支持,需要注意的是IE8,它支持JSON,但如果添加了如下的兼容模式代码,切到IE7模式就不行了(此时依然支持localStorage,虽然显示window.localStorage是[object],而不是之前的[object Storage],但测试发现getItem()、setItem()等均能使用)。

<meta content="IE=7" http-equiv="X-UA-Compatible"/>

提高篇 sessionStorage对象

sessionStorage是要放在服务器上面的,在本地访问时看不到的。sessionStorage对象存储特定于某个会话的数据,也就是该数据只能保持到浏览器关闭。这个对象就像会话cookie,也会在浏览器关闭后消失。存储在sessionStorage中的数据可以跨越页面刷新而存在,同时浏览器支持,浏览器崩溃并重启之后依然可用(firefox 和 webkit 都支持,IE则不行)。

因为sessionStorage对象绑定于摸个服务器会话。所以当文件在本地运行时候是不可用的。存储在sessionStorage中的数据只能由最初给对象存储数据的页面访问到,所以对多页面应用有现在。

sessionStorage对象其实是Storage的一个实例,所以可以使用setItem()或者直接设置新的属性来存储数据

[code] <script type="text/javascript">
//使用方法存储数据
sessionStorage.setItem('name','pingfan');

    //使用属性存储数据
    //sessionStorage.name='pingfan';
</script>[/code]

代码片段 2

HTML5LocalStorage,sessionStorage本地存储

以上ie8也支持哦。

但是不同的浏览器写入数据方面略有不同。firefox和webkit实现了同步写入,所以添加到存储空间的数据室立刻被提交的。而IE的实现则是异步写入数据,所以在设置数据和将数据实际写入磁盘之间可能有一些延迟。对于少量数据而言,这个差异可以忽略。对于大量数据,你发现IE要比其他浏览器更快地恢复执行,因为它会跳过实际的磁盘写入过程。

在IE8中可以强制把数据写入磁盘:在设置数据之前使用begin()方法,并在设置完成之后调用commit()方法。(唉,ie又自搞一套)

[code] //只使用于ie8
sessionStorage.begin();
sessionStorage.name='pingfan';
sessionStorage.age='24';
sessionStorage.commit();[/code]
自己亲自测了一些没成功,搞不懂。

这段代码确保了name和book的值在调用commit()之后立刻被写入磁盘。调用begin()是为了确保在这段代码执行的时候不会发生其他磁盘写入操作。对于少量数据而言,这个过程不是必须的;不过,对于大量数据(如文档之类的)可能就要考虑这种事务形式方法了。

sessionStorage中有数据时,可以使用getItem()或者通过直接访问属性名来获取数据。

[code] //使用方法读取数据
var name=sessionStorage.getItem("name");

//使用属性读取数据

var book=sessionStorage.book;[/code]

还可以通过结合length属性和key()方法来迭代sessionStorage中的值。基本跟localStorage有很多相同之处:

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

这种也行

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

从sessionStorage中删除数据,可以使用delete操作符删除对象属性,也可以用remvoeItem。

[code] //使用delete删除一个值--在webkit中无效
delete sessionStorage.name;

//使用方法删除一个值
sessionStorage.removeItem("book");[/code]

delete操作符在webkit中无法删除,removeItem()都兼容。

sessionStorage对象应该主要用于针对会话的小段数据的存储。如果需哟跨越会话存储数据,那么globalStorage或者localStorage更为合适。

升级篇:globalStorage对象

firefox2中实现了globalStorage对象。作为最初的web Storage规范的一部分,这个对象的目的是跨越会话存储数据,但有特定的访问限制。要使用globalStorage,首先要指定那些域可以访问该数据。可以通方括号标记使用属性实现;

[code]<script type="text/javascript">
//保存数据
globalStorage["www.pingfan.com"].name = "pingfan";

//获取数据

var name=globalStorage["www.pingfan.com"].name;
</script>[/code]

这里所指定的存储空间只能由来自www.wrox.com的页面访问,其他子域名都不行。

某些浏览器允许更加宽泛的访问限制,比如只更具顶级域名进行限制或者允许全局访问:

[code]//存储数据,任何人都可以访问 不这样安全第一
globalStorage[""].name = "pingfan";

//存储数据,让以.net结尾的域名访问
globalStorage["net"].name = "pingfan";[/code]

虽然这些支持,但是还是要避免使用这种可宽泛访问的数据存储,以防止出现潜在的安全问题。考虑到安全问题,这些功能在未来可能会被删除或者是被严格限制,所以不应该依赖于这类功能。当使用global的时候一定要指定一个域名。

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

[color=Red]globalStorage的每个属性都是Storage的实例[/color],因此可以像如下代码中这样使用。

[code]globalStorage["www.pingfan.com"].name='pingfan';
globalStorage["www.pingfan.com"].age='24';

globalStorage["www.pingfan.com"].removeItem("name");
var age=globalStorage["www.pingfan.com"].getItem("book");

//这里面globalStorage["www.pingfan.com"]才是Storage的实例
[/code]

上面的注意:如果你事先不知道域名,那么可以用location.host作为属性名比较安全,如

[code]globalStorage[location.host].name = "pingfan";
var age=globalStorage[location.host].getItem("book");[/code]

如果不使用removeItem()或者delete删除,或者用户未清除浏览器缓存,存储在globalStorage属性中的数据会一直保留在磁盘上。这让globalStorage非常适合在客户端存储文档长期保存用户偏好设置。

说了这么多,来个总结:

localStorage对象在修订的HTML5规范中作为保存客户端数据的方案取代了globalStorage。与globalStorage不同,不能给localStorage指定任何访问规则;规则事先就设定好了。要访问同一个localStorage对象,页面必须来自同一个域名(子域名无效),使用同一种协议,在同一个端口上。这相当于globalStorage[location.host]。

由于localStorage是storage的实例,所以可以使用sessionStorage一样来使用它。即利用属性方式和getItem,setItem方法。

存储在locationStorage中的数据和存储在globalStorage中的数据一样,都遵循相同的规则:数据保留到通过javascript删除或者是用户清楚浏览器缓存。

兼容只支持globalStorage的浏览器: 

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

}[/code]

然后,向下面这样调用一次函数就可以了
[code]
var storage=getLocalStorage();[/code]

storage事件,对storage对象进行任何修改,都会在文档上触发storage事件。监听storage事件:

[code]document.addEventListener("storage", function(event){
alert("Storage changed for" + event.domain);
},false)[/code]

资料信息:http://www.cnblogs.com/xiaowei0705/archive/2011/04/19/2021372.htm

评论 ( 1 )
最新评论
hugeannex 2014-08-20 22:54:56 1F

   不同意把userData说得那么垃圾,至少加工一下也是一个localStorage。。。