初试WebStorage之localstorage
今天小试一下html5中引入的localStorage特性(后来查了下localStorage应该是W3C中Web Storage的一部分,而不是Html5), 这个特性在IE8+中也已支持,其他的浏览器应该都已支持(像chrome, firefox一般都会自动升级到最新). 在学习的过程中也参考了一些文章,比如 Diveintohtml5系列 和 html5demos系列 .总之网上的资源还是很多的.下面就拿出我比较简单的测试代码来 说明一下.
首先来段工具代码, 这段放在外部js中在中引入
1 // 探测浏览器是否支持localStorage 2 var isSupportLocalStorage = function() { 3 try { 4 return 'localStorage' in window && window['localStorage'] != null; 5 } catch (e) { 6 return false; 7 } 8 }; 9 10 // 一段老生常谈的添加事件通用方法, 不过这样写更巧妙些 11 // addEvent会初始化为适合当前浏览器的方法 12 // 不用每次都判断, 而且对IE中eventHandler的调用做了小小的改进 13 // 让eventHandler的执行context为触发事件的元素 14 var addEvent = (function() { 15 if(document.addEventListener) { 16 return function(el, type, fn) { 17 if(el && el.nodeName || el === window) { 18 el.addEventListener(type, fn, false); 19 } else if (el && el.length) { 20 for(var i = 0; i < el.length; i++) { 21 addEvent(el[i], type, fn); 22 } 23 } 24 }; 25 } else { 26 return function(el, type, fn) { 27 if(el && el.nodeName || el === window) { 28 el.attachEvent('on' + type, function() { 29 return fn.call(el, window.event); 30 }); 31 } else if (el && el.length) { 32 for(var i = 0; i < el.length; i++) { 33 addEvent(el[i], type, fn); 34 } 35 } 36 }; 37 } 38 })();
下面是配合测试的html代码, 测试一共两个页面A和B,访问方式是http://localhost:8080/FrontEnd/A.html(B.html), html部分都是相同的. 一个输入框,一个按钮
1 <input id="data" type="text" name="data" /> 2 <button id="saveBtn">save</button>
下面来看页面A.html中的js代码
1 if(isSupportLocalStorage()) { 2 // 清除所有存储的key,value值 3 // localStorage.clear(); 4 5 var dataInput = document.getElementById('data'), 6 saveBtn = document.getElementById('saveBtn'); 7 8 addEvent(saveBtn, 'click', function () { 9 // 按下按钮存下当前输入框中的值 10 localStorage.setItem('storage-event-test', dataInput.value); 11 }); 12 13 // 给window监听storage事件 14 addEvent(window, 'storage', function (event) { 15 // 查看event对象内容 16 // console.dir(event); 17 // 输出oldValue和newValue 以作观察 18 console.log('key: %s, old value: %s, new value: %s', event.key, event.oldValue, event.newValue); 19 }); 20 21 // 存储数字 22 localStorage.setItem('number', 1); 23 // 存储对象 因为localStorage最终都是以String来存储的 所以如果要存储对象 可以覆写它的toString方法 24 // 按照你想要的字符串格式来存储, 然后取出后再做相应的处理, 这里就拿json格式做个例子 25 localStorage.setItem('obj', "{'name':'Andrew', 'job': 'Developer'}"); 26 // 常规的存储 27 localStorage.setItem('string', 'hello world'); 28 29 } else { 30 // 这里可以做些降级的方案, 当然也可以给出一个不支持的提示 31 var span = document.createElement("span"); 32 span.style.color = 'red'; 33 span.innerHTML = 'oops, your browser dones\'t support localStorage yet, :('; 34 document.getElementsByTagName('body')[0].appendChild(span); 35 }
再来看一下B.html中的js代码, 基本和A.html中的相同, 只是中间一段存储代码改成读取而已, 比较简单
1 if(isSupportLocalStorage()) { 2 //localStorage.clear(); 3 4 var dataInput = document.getElementById('data'), 5 saveBtn = document.getElementById('saveBtn'); 6 7 addEvent(saveBtn, 'click', function () { 8 localStorage.setItem('storage-event-test', dataInput.value); 9 }); 10 11 // 给window监听storage事件 12 addEvent(window, 'storage', function (event) { 13 // 查看event对象内容 14 // console.dir(event); 15 // 输出oldValue和newValue 以作观察 16 console.log('key: %s, old value: %s, new value: %s', event.key, event.oldValue, event.newValue); 17 }); 18 19 // 取出来也是String类型的, 要用parseInt转换下 20 console.log(parseInt(localStorage.getItem('number'))); 21 // 取出来的json格式字符串要用eval解析一下 转换成对象 22 console.dir(eval('(' + localStorage.getItem('obj') + ")")); 23 // 普通的读取 24 console.log(localStorage.getItem('string')); 25 26 } else { 27 var span = document.createElement("span"); 28 span.style.color = 'red'; 29 span.innerHTML = 'oops, your browser dones\'t support localStorage yet, :('; 30 document.getElementsByTagName('body')[0].appendChild(span); 31 }
我先在firefox5中进行测试,一开始还遇到了一个可笑的问题, 没有通过启动本地的运用服务器来访问(以http://localhost:8080/...),直接是个静态页面(以file:///"形式), 在firebug下搞了半天也没看到window下的localStorage属性,而且storage事件也根本不触发.放到IE9中,F12开发者工具的调试输出面板中直接报个错, localStorage为null或未定义. 后来google了一下,在stackoverflow中找到了答案, localStorage要通过域名访问的方式才能起作用.总算能继续进行下去了: )
在firefox5中存储和读取都是正常的, 但是对storage事件的触发似乎有点问题, 自身页面进行setItem后没有触发window的storage事件, 但是同时访问A.html和B.html, 在A页面中进行 setItem能触发B页面中window的storage事件, 同样的在B页面中进行setItem能触发A页面中window的storage事件. 在IE9中, 页面自身的设值能触发当前页面的storage事件,同样当前页面的设值能触发同一 "起源" 下其他页面window的storage事件,这看起来似乎更让人想的通些.
关于"起源"这个词 Dev.Opera-WebStorage 中用的是origin. 我就姑且把origin翻译成蹩脚的"起源"吧, 文章最后关于web storage的注意点里有这么一句: Storage per origin:All storage from the same origin will share the same storage space 并且要 协议 + 域名 + 端口 一样才能算同一origin, 这个origin下的页面才能共享一个storage space. 有兴趣的可以去读下此文章.
还有firefox中跨页面触发,好像也有些让人不解. 我的测试结果是这样的(dataInput.value直接用字符串进行代替):
-
A中 setItem('storage-event-test', 'aaaa') -> B的console输出oldValue: , newValue: aaaa
-
B中 setItem('storage-event-test', 'bbbb') -> A的console输出oldValue: , newValue: bbbb
-
A中 setItem('storage-event-test', 'cccc') -> B的console输出oldValue: aaaa, newValue: cccc
-
B中 setItem('storage-event-test', 'dddd') -> A的console输出oldValue: bbbb, newValue: dddd
我所预期的结果是,两个页面应该共享同一个storageArea
-
A中 setItem('storage-event-test', 'aaaa') -> B的console输出oldValue: , newValue: aaaa
-
B中 setItem('storage-event-test', 'bbbb') -> A的console输出oldValue: aaaa, newValue: bbbb
-
A中 setItem('storage-event-test', 'cccc') -> B的console输出oldValue: bbbb, newValue: cccc
-
B中 setItem('storage-event-test', 'dddd') -> A的console输出oldValue: cccc, newValue: dddd
这个结果一看就是不怎么对劲, 好像localStorage中的storageArea是各自独立的,而非对于同一个 "起源" 共享的.但是A页面中的那段存储在B页面中却能正常读取. 在IE9下结果是我所预期的那种. 所以搞到最后我就纳闷了难道是firefox的bug还是我对localStorage的理解还有出入, 如果有园友知道其中的缘由, 希望能留言指导一下, 先谢谢了.
在IE9里发现一个问题,相同的key,不管你value是否与之前一样,都会触发storage事件,而firefox中不会,只有当value与之前不同时,才会触发.