浏览器提供的localStorage本地存储的最大空间是5M,如果不够用呢,这时候就需要考虑来给localStorage扩容。
思路如下:
- 在【A域】下引入【B域】,【A域】空间足够时,读写由【A域】来完成,数据存在【A域】下;当【A域】空间不够时,读写由【B域】来完成,数据存在【B域】下
- 【A域】空间不够需要在【B域】读写时,通过postMessage 向【B域】发送跨域消息,【B域】监听跨域消息,在接到指定的消息时进行读写操作
- 【B域】接到跨域消息时,如果是写入删除可以不做什么,如果是读取,就要先读取本域本地数据通过postMessage向父页面发送消息
- 【A域】在读取【B域】数据时就需要监听来自【B域】的跨域消息
注意事项:
- window.postMessage()方法,向【B域】发消息,应用
window.frames[0].postMessage()
这样iframe内的【B域】才可以接到 - 同理,【B域】向 【A域】发消息时应用,
window.parent.postMessage()
- 【A域】的逻辑一定要在iframe 加载完成后进行
【A域】的页面如下:
index.html
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <body> <button class="set">存储</button> <button class="get">读取</button> <button class="remove">删除</button> <iframe src="http://localhost:8000/storage.html"></iframe> //嵌入【B域】的一个空页面 </body> <script src="js/localStorage.js"></script> </html> |
由于需要判断【A域】的空间是否足够,所以需要计算【A域】已经被占用的空间。那么localStorage中的字符串以什么编码格式存储的呢?
经过反复试验发现,当使用utf-16的编码方式进行计算时,当存储的字符串大于5M时,浏览区就会报错:字符串大小超过最大值。
所以localStorage中的字符串是以utf-16进行编码的。
localStorage.js
0 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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
/*这段代码是用来测试localStorage中字符串的编码格式*/ /** * 计算字符串所占的内存字节数,默认使用UTF-8的编码方式计算,也可制定为UTF-16 * UTF-8 是一种可变长度的 Unicode 编码格式,使用一至四个字节为每个字符编码 * * 000000 - 00007F(128个代码) 0zzzzzzz(00-7F) 一个字节 * 000080 - 0007FF(1920个代码) 110yyyyy(C0-DF) 10zzzzzz(80-BF) 两个字节 * 000800 - 00D7FF 00E000 - 00FFFF(61440个代码) 1110xxxx(E0-EF) 10yyyyyy 10zzzzzz 三个字节 * 010000 - 10FFFF(1048576个代码) 11110www(F0-F7) 10xxxxxx 10yyyyyy 10zzzzzz 四个字节 * * 注: Unicode在范围 D800-DFFF 中不存在任何字符 * * UTF-16 大部分使用两个字节编码,编码超出 65535 的使用四个字节 * 000000 - 00FFFF 两个字节 * 010000 - 10FFFF 四个字节 * * @param {String} str * @param {String} charset utf-8, utf-16 * @return {Number} */ function sizeof(str,charset){ var strCode=0,charCode; charset = charset?charset.toLowerCase():''; if(charset=='utf-16'||charset=='utf16'){ for(var i=0,len=str.length;i<len;i++){ charCode = str.charCodeAt(i); strCode += charCode<0xffff?2:4; } }else{ for(var i=0,len=str.length;i<len;i++){ charCode = str.charCodeAt(i); strCode += (charCode<0x007f&&1)||(charCode<0x07ff&&2)||(charCode<0xffff&&3)||4; } } return strCode/1024/1024/2; } /*测试localStorage中字符串的编码格式结束*/ function storage(type,key,value){ var val = localStorage.getItem(key); switch (type){ case 'get': if(val){ return val; }else{ return window.frames[0].postMessage(JSON.stringify({type:type,key:key}),'http://localhost:8000'); } break; case 'set': if(!val&&sizeofLocal()+sizeof(value)>5){ window.frames[0].postMessage(JSON.stringify({type:type,key:key,value:value}),'http://localhost:8000'); }else{ localStorage.setItem(key,value); } break; case 'remove': if(val){ localStorage.removeItem(key); }else{ window.frames[0].postMessage(JSON.stringify({type:type,key:key}),'http://localhost:8000'); } break; default: break; } } function sizeofLocal(){ var myStr = '',charCode,strCode=0; for(item in localStorage){ if(localStorage.hasOwnProperty(item)){ myStr += localStorage.getItem(item); } } for(var i=0,len=myStr.length;i<len;i++){ charCode = myStr.charCodeAt(i); strCode += charCode<0xffff?2:4; } return strCode/1024/1024/2; } var myStr=''; for(var i=0;i<1024*1200;i++){ myStr += 1+'12'+'啦'; } document.querySelector(".set").onclick = function(){ storage("set","yoyo",myStr); } document.querySelector(".get").onclick = function(){ storage("get","yoyo"); window.addEventListener('message',function(e){ window.myStorage = e.data; }) } document.querySelector(".remove").onclick = function(){ storage("remove","yoyo"); } |
【B域】的页面如下
storage.html
0 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 38 39 40 41 42 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <body> </body> <script type="text/javascript"> var fn = function(){}; fn.prototype = { setLocal:function(key,value){ localStorage.setItem(key,value); }, getLocal:function(key){ return localStorage.getItem(key); }, removeLocal:function(key){ localStorage.removeItem(key); }, bindEvent:function(){ var self = this; //监听 window.addEventListener('message',function(e){ if(window.parent!=e.source) return; var option = JSON.parse(e.data); if(option.type.toLowerCase()=="get"){ var data = self.getLocal(option.key); window.parent.postMessage(data,'*'); } option.type.toLowerCase()=="set"&&self.setLocal(option.key,option.value); option.type.toLowerCase()=="remove"&&self.removeLocal(option.key); }) }, init:function(){ var self = this; self.bindEvent(); } } var tools = new fn(); tools.init(); </script> |