├── README.md └── browser-storage.js /README.md: -------------------------------------------------------------------------------- 1 | 基于浏览器的缓存策略(browser-storage) 2 | ========================== 3 | 浏览器本地存储的一个解决方案,存储优先级依次为:HTML5-localStorage > IE-UserData > Cookie;并提供一套友好的API,对本地存储数据进行批量存储、读取、移除、清空等操作 4 | 5 | ### 简介 6 | ```javascript 7 | /** 8 | * 全浏览器支持的本地存储方案:browser-storage.js 9 | * 10 | * @detail 11 | * 1、支持HTML5的浏览器,采用原生localStorage进行存储 12 | * 2、IE7及其以下版本,采用UserData进行存储 13 | * 3、在以上两种都不支持的浏览器中,采用cookie进行存储 14 | * 15 | * @API 16 | * 1、BrowserStorage.api.setUserDataEnabled //设置IE中是否采用UserData存储 17 | * 2、BrowserStorage.api.set //设置本地存储 18 | * 3、BrowserStorage.api.get //获取本地存储 19 | * 4、BrowserStorage.api.remove //移除本地存储 20 | * 5、BrowserStorage.api.clearAll //清空所有本地存储 21 | * 6、BrowserStorage.api.getAllKeys //获取所有本地存储的key 22 | * 23 | */ 24 | ``` 25 | 26 | ### 详细api文档 27 | http://www.baidufe.com/component/browser-storage/index.html -------------------------------------------------------------------------------- /browser-storage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 全浏览器支持的本地存储方案:browser-storage.js 3 | * 4 | * @detail 5 | * 1、支持HTML5的浏览器,采用原生localStorage进行存储 6 | * 2、IE7及其以下版本,采用UserData进行存储 7 | * 3、在以上两种都不支持的浏览器中,采用cookie进行存储 8 | * 9 | * @API 10 | * 1、BrowserStorage.api.setUserDataEnabled //设置IE中是否采用UserData存储 11 | * 2、BrowserStorage.api.set //设置本地存储 12 | * 3、BrowserStorage.api.get //获取本地存储 13 | * 4、BrowserStorage.api.remove //移除本地存储 14 | * 5、BrowserStorage.api.clearAll //清空所有本地存储 15 | * 6、BrowserStorage.api.getAllKeys //获取所有本地存储的key 16 | * 17 | * @homepage http://www.baidufe.com/component/browser-storage/index.html 18 | * @author zhaoxianlie (xianliezhao@foxmail.com) 19 | */ 20 | var BrowserStorage = window.BrowserStorage || { 21 | version : '1.3' 22 | }; 23 | 24 | /** 25 | * ==================================================================== 26 | * window.localStorage的相关处理 27 | * 28 | * 1、存储一个内容到本地 29 | * 2、读取一个本地存储 30 | * 3、移除一个本地存储 31 | * 4、移除全部本地存储 32 | * 5、获取所有本地存储的key 33 | * ==================================================================== 34 | */ 35 | BrowserStorage.localStorage = (function(){ 36 | 37 | /** 38 | * 将数据进行本地存储(只能存储字符串信息) 39 | */ 40 | function _set(storageInfo){ 41 | //待存储的数据 42 | var storageInfo = storageInfo || {}; 43 | window.localStorage.setItem(storageInfo.key,storageInfo.value); 44 | 45 | // 如果指定了生命周期,则单独作为一个key来存储 46 | if(storageInfo.expires) { 47 | var expires; 48 | //如果设置项里的expires为数字,则表示数据的能存活的毫秒数 49 | if ('number' == typeof storageInfo.expires) { 50 | expires = new Date(); 51 | expires.setTime(expires.getTime() + storageInfo.expires); 52 | } 53 | 54 | window.localStorage.setItem(storageInfo.key + ".expires",expires || storageInfo.expires); 55 | } 56 | } 57 | 58 | /** 59 | * 提取本地存储的数据 60 | */ 61 | function _get(config){ 62 | //结果 63 | var result = null; 64 | if(typeof config === "string") config = {key : config}; 65 | 66 | result = window.localStorage.getItem(config.key); 67 | //过期时间判断,如果过期了,则移除该项 68 | if(result) { 69 | var expires = window.localStorage.getItem(config.key + ".expires"); 70 | result = { 71 | value : result, 72 | expires : expires ? new Date(expires) : null 73 | }; 74 | if(result && result.expires && result.expires < new Date()) { 75 | result = null; 76 | window.localStorage.removeItem(config.key); 77 | window.localStorage.removeItem(config.key + ".expires"); 78 | } 79 | } 80 | return result ? result.value : null; 81 | } 82 | 83 | /** 84 | * 移除某一项本地存储的数据 85 | */ 86 | function _remove(config){ 87 | window.localStorage.removeItem(config.key); 88 | window.localStorage.removeItem(config.key + ".expires"); 89 | } 90 | 91 | /** 92 | * 清除所有本地存储的数据 93 | */ 94 | function _clearAll(){ 95 | window.localStorage.clear(); 96 | } 97 | 98 | /** 99 | * 获取所有的本地存储数据对应的key 100 | */ 101 | function _getAllKeys(){ 102 | var result = [],key; 103 | for(var i = 0,len = window.localStorage.length;i < len;i++){ 104 | key = window.localStorage.key(i); 105 | if(!/.+\.expires$/.test(key)) { 106 | result.push(key); 107 | } 108 | } 109 | return result; 110 | } 111 | 112 | return { 113 | get : _get, 114 | set : _set, 115 | remove : _remove, 116 | clearAll : _clearAll, 117 | getAllKeys : _getAllKeys 118 | }; 119 | })(); 120 | 121 | 122 | /** 123 | * ==================================================================== 124 | * userData的相关处理 125 | * 126 | * 1、存储一个内容到本地 127 | * 2、读取一个本地存储 128 | * 3、移除一个本地存储 129 | * 4、移除全部本地存储 130 | * 5、获取所有本地存储的key 131 | * ==================================================================== 132 | */ 133 | BrowserStorage.userData = (function(){ 134 | 135 | //所有的key 136 | var _clearAllKey = "_baidu.ALL.KEY_"; 137 | 138 | /** 139 | * 创建并获取这个input:hidden实例 140 | * @return {HTMLInputElement} input:hidden实例 141 | * @private 142 | */ 143 | function _getInstance(){ 144 | //把UserData绑定到input:hidden上 145 | var _input = null; 146 | //是的,不要惊讶,这里每次都会创建一个input:hidden并增加到DOM树种 147 | //目的是避免数据被重复写入,提早造成“磁盘空间写满”的Exception 148 | _input = document.createElement("input"); 149 | _input.type = "hidden"; 150 | _input.addBehavior("#default#userData"); 151 | document.body.appendChild(_input); 152 | return _input; 153 | } 154 | 155 | /** 156 | * 将数据通过UserData的方式保存到本地,文件名为:文件名为:config.key[1].xml 157 | * @param {Object} config 待存储数据相关配置 158 | * @cofnig {String} key 待存储数据的key 159 | * @config {String} value 待存储数据的内容 160 | * @config {String|Object} [expires] 数据的过期时间,可以是数字,单位是毫秒;也可以是日期对象,表示过期时间 161 | * @private 162 | */ 163 | function __setItem(config){ 164 | try { 165 | var input = _getInstance(); 166 | //创建一个Storage对象 167 | var storageInfo = config || {}; 168 | //设置过期时间 169 | if(storageInfo.expires) { 170 | var expires; 171 | //如果设置项里的expires为数字,则表示数据的能存活的毫秒数 172 | if ('number' == typeof storageInfo.expires) { 173 | expires = new Date(); 174 | expires.setTime(expires.getTime() + storageInfo.expires); 175 | } 176 | expires = (expires || storageInfo.expires); 177 | input.expires = expires.toUTCString(); 178 | } 179 | 180 | //存储数据 181 | input.setAttribute(storageInfo.key,storageInfo.value); 182 | //存储到本地文件,文件名为:storageInfo.key[1].xml 183 | input.save(storageInfo.key); 184 | } catch (e) { 185 | } 186 | } 187 | 188 | /** 189 | * 将数据通过UserData的方式保存到本地,文件名为:文件名为:config.key[1].xml 190 | * @param {Object} config 待存储数据相关配置 191 | * @cofnig {String} key 待存储数据的key 192 | * @config {String} value 待存储数据的内容 193 | * @config {String|Object} [expires] 数据的过期时间,可以是数字,单位是毫秒;也可以是日期对象,表示过期时间 194 | * @private 195 | */ 196 | function _set(config){ 197 | //保存有效内容 198 | __setItem(config); 199 | 200 | //下面的代码用来记录当前保存的key,便于以后clearAll 201 | var result = _get({key : _clearAllKey}); 202 | if(result) { 203 | result = { key : _clearAllKey, value : result }; 204 | } else { 205 | result = { key : _clearAllKey, value : "" }; 206 | } 207 | 208 | if(!(new RegExp("(^|\\|)" + config.key + "(\\||$)",'g')).test(result.value)) { 209 | result.value += "|" + config.key; 210 | //保存键 211 | __setItem(result); 212 | } 213 | } 214 | 215 | /** 216 | * 提取本地存储的数据 217 | * @param {String} config 待获取的存储数据相关配置 218 | * @cofnig {String} key 待获取的数据的key 219 | * @return {String} 本地存储的数据,获取不到时返回null 220 | * @example 221 | * qext.LocalStorage.get({ 222 | * key : "username" 223 | * }); 224 | * @private 225 | */ 226 | function _get(config){ 227 | try { 228 | var input = _getInstance(); 229 | //载入本地文件,文件名为:config.key[1].xml 230 | input.load(config.key); 231 | //取得数据 232 | return input.getAttribute(config.key) || null; 233 | } catch (e) { 234 | return null; 235 | } 236 | } 237 | 238 | /** 239 | * 移除某项存储数据 240 | * @param {Object} config 配置参数 241 | * @cofnig {String} key 待存储数据的key 242 | * @private 243 | */ 244 | function _remove(config){ 245 | try { 246 | var input = _getInstance(); 247 | //载入存储区块 248 | input.load(config.key); 249 | //移除配置项 250 | input.removeAttribute(config.key); 251 | //强制使其过期 252 | var expires = new Date(); 253 | expires.setTime(expires.getTime() - 1); 254 | input.expires = expires.toUTCString(); 255 | input.save(config.key); 256 | 257 | //从allkey中删除当前key 258 | //下面的代码用来记录当前保存的key,便于以后clearAll 259 | var result = _get({key : _clearAllKey}); 260 | if(result) { 261 | result = result.replace(new RegExp("(^|\\|)" + config.key + "(\\||$)",'g'),''); 262 | result = { key : _clearAllKey, value : result }; 263 | //保存键 264 | __setItem(result); 265 | } 266 | 267 | } catch (e) { 268 | } 269 | } 270 | 271 | //移除所有的本地数据 272 | function _clearAll(){ 273 | result = _get({key : _clearAllKey}); 274 | if(result) { 275 | var allKeys = result.split("|"); 276 | var count = allKeys.length; 277 | for(var i = 0;i < count;i++){ 278 | if(!!allKeys[i]) { 279 | _remove({key:allKeys[i]}); 280 | } 281 | } 282 | } 283 | } 284 | 285 | /** 286 | * 获取所有的本地存储数据对应的key 287 | * @return {Array} 所有的key 288 | * @private 289 | */ 290 | function _getAllKeys(){ 291 | var result = []; 292 | var keys = _get({key : _clearAllKey}); 293 | if(keys) { 294 | keys = keys.split('|'); 295 | for(var i = 0,len = keys.length;i < len;i++){ 296 | if(!!keys[i]) { 297 | result.push(keys[i]); 298 | } 299 | } 300 | } 301 | return result ; 302 | } 303 | 304 | return { 305 | get : _get, 306 | set : _set, 307 | remove : _remove, 308 | clearAll : _clearAll, 309 | getAllKeys : _getAllKeys 310 | }; 311 | })(); 312 | 313 | 314 | /** 315 | * ==================================================================== 316 | * cookie的相关处理 317 | * 318 | * 1、存储一个内容到本地 319 | * 2、读取一个本地存储 320 | * 3、移除一个本地存储 321 | * 4、移除全部本地存储 322 | * 5、获取所有本地存储的key 323 | * ==================================================================== 324 | */ 325 | BrowserStorage.cookie = (function(){ 326 | /** 327 | * 判断某key是否合法 328 | * @param key 329 | * @return {Boolean} 330 | * @private 331 | */ 332 | var _isValidKey = function(key) { 333 | return (new RegExp("^[^\\x00-\\x20\\x7f\\(\\)<>@,;:\\\\\\\"\\[\\]\\?=\\{\\}\\/\\u0080-\\uffff]+\x24")).test(key); 334 | }; 335 | 336 | /** 337 | * 获取存储在cookie中的内容 338 | * @param config 存储信息 339 | * @config key cookie-key 340 | * @config decode 是否进行decode处理 341 | * @return {String} 342 | * @private 343 | */ 344 | var _get = function(config) { 345 | var value = null; 346 | if (_isValidKey(config.key)) { 347 | var reg = new RegExp("(^| )" + config.key + "=([^;\/]*)([^;\x24]*)(;|\x24)"), result = reg.exec(document.cookie); 348 | 349 | if (result) { 350 | value = result[2] || null; 351 | } 352 | } 353 | if (('string' == typeof value) && config.decode != false) { 354 | value = decodeURIComponent(value); 355 | return value; 356 | } 357 | return null; 358 | }; 359 | 360 | /** 361 | * 存储cookie 362 | * 363 | * @param options { 364 | * key : "", 365 | * value : "", 366 | * path : "", // 默认存储在当前域名的根目录,如果要设置到每个页面的单独目录,请设置为:"./" 367 | * domain : "", 368 | * expires : Date, 369 | * secure : "secure", 370 | * encode : true 371 | * } 372 | * @private 373 | */ 374 | var _set = function(config) { 375 | if (!_isValidKey(config.key)) { 376 | return; 377 | } 378 | 379 | config = config || {}; 380 | if(config.encode != false){ 381 | config.value = encodeURIComponent(config.value); 382 | } 383 | 384 | // 计算cookie过期时间 385 | var expires = config.expires; 386 | if(!(expires instanceof Date)) { 387 | expires = new Date(); 388 | if ('number' == typeof config.expires) { 389 | expires.setTime(expires.getTime() + config.expires * 1000); 390 | }else{ 391 | // 在没有设置过期时间的情况下,默认:30day 392 | expires.setTime(expires.getTime() + 86400000*30); 393 | } 394 | } 395 | 396 | document.cookie = config.key + "=" + config.value 397 | + ("; path=" + (config.path ? (config.path == './' ? '' : config.path) : "/")) 398 | + (expires ? "; expires=" + expires.toGMTString() : "") 399 | + (config.domain ? "; domain=" + config.domain : "") 400 | + (config.secure ? "; secure" : ''); 401 | }; 402 | 403 | /** 404 | * 移除掉某一个存储 405 | * @param config 406 | * @config key 407 | * @private 408 | */ 409 | var _remove = function(config){ 410 | var obj = _get(config); 411 | if(obj != null) { 412 | config.value = null; 413 | config.expires = -1; 414 | _set(config); 415 | } 416 | }; 417 | 418 | /** 419 | * 清除掉所有 420 | * @private 421 | */ 422 | var _clearAll = function(){ 423 | document.cookie = ''; 424 | }; 425 | 426 | /** 427 | * 获取所有的存储key 428 | * @private 429 | */ 430 | var _getAllKeys = function(){ 431 | var keys = []; 432 | var reg = /(^| )([^=; ]+)=([^;]*)(;|\x24)/igm; 433 | var localCookies = (document.cookie || '').match(reg); 434 | if(localCookies) { 435 | var items; 436 | for(var i= 0,len=localCookies.length;i@,;:\\\\\\\"\\[\\]\\?=\\{\\}\\/\\u0080-\\uffff]+\x24")).test(key); 506 | }; 507 | 508 | /** 509 | * 将数据进行本地存储(只能存储字符串信息) 510 | * 511 | * @example 512 | * BrowserStorage.api.set({ 513 | * key : "username", 514 | * value : "baiduie", 515 | * expires : 3600 * 1000 516 | * }); 517 | * //保存对个对象 518 | * BrowserStorage.api.set([{ 519 | * key : "username", 520 | * value : "baiduie", 521 | * expires : 3600 * 1000 522 | * },{ 523 | * key : "password", 524 | * value : "zxlie", 525 | * expires : 3600 * 1000 526 | * }]); 527 | * 528 | * @param {Object/Array} obj 待存储数据相关配置,可以是单个JSON对象,也可以是由多个JSON对象组成的数组 529 | * @p-config {String} key 待存储数据的key,如:baidu.username 530 | * @p-config {String} value 待存储数据的内容 531 | * @p-config {String} path cookie专用,默认为:根目录:"/",要设置到当前目录,则是:"./" 532 | * @p-config {String} domain cookie专用,默认为:当前域名 533 | * @p-config {Number/Date} expires 数据的过期时间,可以是数字,单位是毫秒;也可以是日期对象,表示过期时间, 534 | * 如果未设置expires,或设置不合法时,组件会默认将其设置为30天 535 | * @param {Boolean} enableUD 参数可选;是否在IE7及其以下版本中启用UserData,默认:false 536 | */ 537 | var _set = function(obj, enableUD){ 538 | //保存单个对象 539 | var _set_ = function(config){ 540 | //key校验 541 | if(!_isValidKey(config.key)) {return;} 542 | 543 | // 计算cookie过期时间 544 | var expires = config.expires; 545 | if(!(expires instanceof Date)) { 546 | expires = new Date(); 547 | if ('number' == typeof config.expires) { 548 | expires.setTime(expires.getTime() + config.expires); 549 | }else{ 550 | // 在没有设置过期时间的情况下,默认:30day 551 | expires.setTime(expires.getTime() + 86400*30); 552 | } 553 | } 554 | config.expires = expires; 555 | 556 | if(_isSupportLocalStorage()) { 557 | BrowserStorage.localStorage.set(config); 558 | } else if(_isSupportUserData() && enableUD) { 559 | BrowserStorage.userData.set(config); 560 | } else { 561 | BrowserStorage.cookie.set(config); 562 | } 563 | }; 564 | 565 | //判断传入的参数是否为数组 566 | if(obj && obj.constructor === Array && obj instanceof Array){ 567 | for(var i = 0,len = obj.length;i < len;i++){ 568 | _set_(obj[i]); 569 | } 570 | }else if(obj){ 571 | _set_(obj); 572 | } 573 | }; 574 | 575 | /** 576 | * 提取本地存储的数据 577 | * 578 | * @example 579 | * //获取某一个本地存储,返回值为:{key:"",value:""},未取到值时,对应value为空 580 | * var rst = BrowserStorage.api.get({ 581 | * key : "username" 582 | * }); 583 | * //获取多个本地存储,返回值为:[{key:"",value:""},{key:"",value:""}] 584 | * BrowserStorage.api.get([{ 585 | * key : "username" 586 | * },{ 587 | * key : "password" 588 | * }]); 589 | * 590 | * @param {String/Object/Array} obj 待获取的存储数据相关配置,支持单个对象传入,同样也支持多个对象封装的数组格式 591 | * @p-config {String} key 待存储数据的key 592 | * @param {Boolean} enableUD 参数可选;是否在IE7及其以下版本中启用UserData,默认:false 593 | * @return {Object/Array} 本地存储的数据,传入为单个对象时,返回单个对象;传入为数组时,返回为数组 594 | */ 595 | var _get = function(obj, enableUD){ 596 | //获取某一个本地存储 597 | var _get_ = function(config){ 598 | //结果 599 | var result = null; 600 | if(typeof config === "string") config = {key : config}; 601 | //key校验 602 | if(!_isValidKey(config.key)) {return result;} 603 | 604 | if(_isSupportLocalStorage()) { 605 | result = BrowserStorage.localStorage.get(config); 606 | } else if(_isSupportUserData() && enableUD) { 607 | result =BrowserStorage.userData.get(config); 608 | } else { 609 | result =BrowserStorage.cookie.get(config); 610 | } 611 | 612 | return {key:config.key,value:result} ; 613 | }; 614 | 615 | var rst = null; 616 | //判断传入的参数是否为数组 617 | if(obj && obj.constructor === Array && obj instanceof Array){ 618 | rst = []; 619 | for(var i = 0,len = obj.length;i < len;i++){ 620 | rst.push(_get_(obj[i])); 621 | } 622 | }else if(obj){ 623 | rst = _get_(obj); 624 | } 625 | return rst; 626 | }; 627 | 628 | /** 629 | * 移除本地存储的数据 630 | * 631 | * @example 632 | * //删除一个本地存储项 633 | * BrowserStorage.api.remove({ 634 | * key : "username" 635 | * }); 636 | * 637 | * BrowserStorage.api.remove("username"); 638 | * 639 | * //删除多个本地存储项目 * 640 | * BrowserStorage.api.remove([{ 641 | * key : "username" 642 | * },{ 643 | * key : "password" 644 | * },{ 645 | * key : "sex" 646 | * }]); 647 | * 648 | * @param {String/Object/Array} obj 待移除的存储数据相关配置,支持移除某一个本地存储,也支持数组形式的批量移除 649 | * @p-config {String} key 待移除数据的key 650 | * @p-config {String} path cookie专用,默认为:根目录:"/",要设置到当前目录,则是:"./" 651 | * @p-config {String} domain cookie专用,默认为:当前域名 652 | * @param {Boolean} enableUD 参数可选;是否在IE7及其以下版本中启用UserData,默认:false 653 | */ 654 | var _remove = function(obj, enableUD){ 655 | //移除某一项本地存储的数据 656 | var _remove_ = function(config){ 657 | 658 | if(typeof config === "string") config = {key : config}; 659 | //key校验 660 | if(!_isValidKey(config.key)) {return result;} 661 | 662 | if(_isSupportLocalStorage()) { 663 | BrowserStorage.localStorage.remove(config); 664 | } else if(_isSupportUserData() && enableUD) { 665 | BrowserStorage.userData.remove(config); 666 | } else { 667 | BrowserStorage.cookie.remove(config); 668 | } 669 | }; 670 | 671 | //判断传入的参数是否为数组 672 | if(obj && obj.constructor === Array && obj instanceof Array){ 673 | for(var i = 0,len = obj.length;i < len;i++){ 674 | _remove_(obj[i]); 675 | } 676 | }else if(obj){ 677 | _remove_(obj); 678 | } 679 | }; 680 | 681 | /** 682 | * 清除所有本地存储的数据 683 | * 684 | * @example 685 | * BrowserStorage.api.clearAll(); 686 | * 687 | * @param {Boolean} enableUD 参数可选;是否在IE7及其以下版本中启用UserData,默认:false 688 | */ 689 | var _clearAll = function(enableUD){ 690 | if(_isSupportLocalStorage()) { 691 | BrowserStorage.localStorage.clearAll(); 692 | } else if(_isSupportUserData() && enableUD) { 693 | BrowserStorage.userData.clearAll(); 694 | } else { 695 | BrowserStorage.cookie.clearAll(); 696 | } 697 | }; 698 | 699 | /** 700 | * 获取所有的本地存储数据对应的key 701 | * 702 | * @example 703 | * var keys = BrowserStorage.api.getAllKeys(); 704 | * 705 | * @param {Boolean} enableUD 参数可选;是否在IE7及其以下版本中启用UserData,默认:false 706 | * @return {Array} 所有的key 707 | */ 708 | var _getAllKeys = function(enableUD){ 709 | var result = null; 710 | 711 | if(_isSupportLocalStorage()) { 712 | result = BrowserStorage.localStorage.getAllKeys(); 713 | } else if(_isSupportUserData() && enableUD) { 714 | result = BrowserStorage.userData.getAllKeys(); 715 | } else { 716 | result = BrowserStorage.cookie.getAllKeys(); 717 | } 718 | 719 | return result; 720 | }; 721 | 722 | return { 723 | get : _get, 724 | set : _set, 725 | remove : _remove, 726 | clearAll : _clearAll, 727 | getAllKeys : _getAllKeys 728 | }; 729 | 730 | })(); 731 | --------------------------------------------------------------------------------