同样是html5的规范,同样是存储,HTML5本地存储和离线存储不是一回事,感觉有必要提及,因为在互联网铺天盖地宣传html5的特性的时候,经常出现这样那样的字眼,对于还没接触的或初学者来说,很容易混淆这两个概念。离线存储(Offline Storage)正如之前我的那篇介绍中你看到的样子,实际上它实现的是文件的离线存储,而本地存储(Local Storage)跟会话存储(Session Storage)一样同属于web的数据存储(Web Storage)。还有一种存储方式是Web SQL Database,它是一个可以用SQL操作的客户端数据库。这些存储方式都是用户客户端实现的,因此有人会把它们称为“本地存储”,实际上我觉得叫“客户端存储”更合适,这样不至于跟Web Storage中的Local Storage概念冲突和混淆。
什么是HTML5 Local Storage?
HTML5中介绍的Local Storage(有的地方把它叫做DOM Storage)是一种将web数据存储在用户本地的存储方式,这种形式的存储其实你早就接触过了,那就是cookie。那么为什么不直接用cookie好了,还要本地存储做什么?我们知道,html5带来更丰富的web表现形式,在web中实现大量富媒体应用的时候,对于数据存储的要求也相对提高,当然服务器的压力也相应变大,因此我们需要一种类似于cookie的存储方式,但它和cookie不大一样:
- 我们需要更大的存储空间,本地存储默认有5MB,而cookie只能存4k的数据
- 和cookie一样都存储在客户端的
- 数据不会因为页面刷新或关闭等操作而改变
- 不会向服务器发出请求,cookie是会包含在每个HTTP请求中的
好吧,假设你现在正需要这样的一种存储方式,那么你要知道浏览器的支持情况如何,支持本地存储的浏览器版本有:IE8+,FIREFOX3.5+,SAFARI4+,CHROME4+,OPERA10.5+,IPHONE2+,ANDROID2+以及其他我不知道的。
如何使用HTML5 Local Storage?
不是所有的浏览器都支持html5的本地存储,所以在使用它之前,你需要一点检测工作,来确保你的应用正常运作,你需要下面的代码:
1 |
if('localStorage' in window&&window['localStorage'] !== null){/* do storage stuff... */} |
Local Storage实现了Storage接口,该接口的原型如下:
interface Storage {
readonly attribute unsigned long length;
getter DOMString key(in unsigned long index);
getter any getItem(in DOMString key);
setter creator void setItem(in DOMString key, in any data);
deleter void removeItem(in DOMString key);
void clear();
};
Local Storage是以键值对(key/value)的形式存储的,每个键值对称为一个项(item);length属性返回项的数量;key(n)返回列表中第n个key的名字;getItem和setItem分别是取值和赋值的方法,如果要取值的key不存在返回null,如果赋值的key存在就覆盖,不存在就新建一个项;removeItem可以清除给定的key所对应的项,如果key不存在则什么都不做;clear会清除所有的项,如果列表本来就是空的就什么都不做。请不要忽略这段话的解释,而且要注意“什么都不做”这几个字是有重要作用的,在你需要实现对存储过程的监控的时候尤为重要!你可能会因为做了某个操作却没有触发相应的事件监听器而感到疑惑,原因就在于“什么都不做”。
看完Storage接口后,我们就可以来做实验了,看看如下代码(查看完整Demo):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>HTML5 Local Storage</title> </head> <body> <h1>你好,<span id="name">我好像不认识你</span></h1> <p><button type="button" onclick="rmMem()">忘记我吧!</button></p> <script type="text/javascript"> <!-- window.onload=function(){ if(('localStorage' in window) && window['localStorage'] !== null){ var name=localStorage.getItem('name'); if(name==null){ name=prompt("你的名字是?",'丸子'); if(name!=null){ localStorage.setItem('name',name); document.getElementById('name').innerHTML=name; } }else{ document.getElementById('name').innerHTML=name; } }else{ alert('天啊,你还在用这么土的浏览器!'); } } function rmMem(){ document.getElementById('name').innerHTML='我好像不认识你'; localStorage.removeItem('name'); alert('清除记忆成功!'); } //--> </script> </body> </html> |
你可能还会看到这样的写法:
1 |
localStorage.setItem(1,'some values'); |
这样不代表该项就是第一项,数字1会被转换为string,因为key的类型就是字符串。
除了接口中那样通过getter跟setter的方式对本地存储的数据进行读写,我们还可以像对象属性访问一样读取与写入数据:
1 2 |
localStorage.name='wanz'; localStorage['name']='wanz'; |
本地存储事件监听
事件监听对于处理存储的异常还是必需的,先来看看StorageEvent 接口的定义:
interface StorageEvent : Event {
readonly attribute DOMString key;
readonly attribute any oldValue;
readonly attribute any newValue;
readonly attribute DOMString url;
readonly attribute Storage storageArea;
void initStorageEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in any oldValueArg, in any newValueArg, in DOMString urlArg, in Storage storageAreaArg);
};
initStorageEvent可以不用管,它负责事件初始化;key返回的是被修改的key;oldValue和newValue分别返回key修改前和修改后的值;url返回修改该key的文档页面地址,有的浏览器可能会叫uri;storageArea返回受影响的Storage对象。
一个简单的存储事件监听的方式可以像下面的代码这样,有经验的同学都知道怎么扩展了,兼容IE不知道的自己google。
1 |
addEventListener('storage',ev_handler,false); |
不管是setItem(), removeItem()还是 clear()操作,各个存储事件只有在存储内容真正发生变化时才会被触发,这也是之前我强调了“什么都不做”的原因。到目前为止,我用http://www.quirksmode.org/dom/tests/html5_storage.html这个页面测试了IE8,FIREFOX3.6.8,CHROME6.0.496和SAFARI5.0.1发现只有IE8跟FF对事件监听有反应,不过返回的StorageEvent的各个属性值基本都是undefined,而CHROME和SAFARI则没有反应,个人猜测是浏览器对存储事件监听的实现还不完善,不排除代码问题,有兴趣的同学自己做测试,我就不给出DEMO了。
另外,出于浏览器安全限制的考虑,大家在测试代码的时候,一定要在服务器环境下,切记!