Vue中localstorage和sessionstorage的使用规范

1. 项目使用中暴露出来的几个问题

  • 大家到处直接使用localstorage['aaa']='这是一段示例字符串'这些原生语法实现,这样耦合度太高了,假如有一天我们需要换实现方式,或者对存储大小做一些控制,那么需要修改的代码就会很多
  • 项目很大,那么大家起的key的名字难免会重复,而且这样也会造成全局污染
  • 因为localstorage的使用不规范,所以造成了存储空间的浪费和不够用

2. 解决办法

  • 封装storage的使用方法,统一处理
  • 规范storage的key值的命名规则
  • 规范storage的使用规范

2.1. 封装统一的方法

  • 封装成方法可以降低耦合度,可以方便切换实现方式,可以控制存储量大小
  • 改变实现可以通过配置不同的参数来实现
  • 编辑如图所示的项目结构

  • 代码实现
/*  * storage.js  */  /*  * @Author: 石国庆  * @Desc: 本地数据存储方法封装  * @Date: 2017.11.14  * @Ref:  *      https://github.com/WQTeam/web-storage-cache  *      https://developer.mozilla.org/en-US/docs/Web/API/Storage/LocalStorage  * @Explain:为了不new对象,只能多写几遍  * @Example:  *  * 1、LocalStorage的使用  * import storage from '@/utils/storage.js'  * storage.setItem('shiguoqing0',[1,2,3,4,5,6])  * storage.setItem('shiguoqing1',{userId:'dfdf',token:11232323})  * storage.setItem('shiguoqing2','dfdfdf')  * console.log(storage.getItem('shiguoqing0'))  * console.log(storage.getItem('shiguoqing1'))  * console.log(storage.getItem('shiguoqing2'))  * storage.removeItem('shiguoqing2')  *  *  * 2、SessionStorage的使用  * storage.setItem('shiguoqing0',[1,2,3,4,5,6],{type:'session'})  *  * */  // TODO:其他方法的实现 // TODO:超时时间的设置  /*  * 方法实现  * */ import local from './storage/localstorage.js' import session from './storage/session.js' import cookies from './storage/cookies.js' import json from './storage/json.js'  /* * 函数体 * */ let storage= {     config:{         type:'local',// local,session,cookies,json         expires:new Date().getTime() + 100 * 24 * 60 * 60 * 1000     },     getStorage(options){         let config={}         if(options){             config=Object.assign({},this.config,options)         }else{             config=this.config         }         return this.createStorage(config.type)     },     createStorage(name){         switch(name){             case 'local':return local;break             case 'session':return session;break             case 'cookies':return cookies;break             case 'json':return json;break         }     },     getItem(key,options){         let store=this.getStorage(options)         return store.getItem(key)     },     setItem(key, value,options){         let store=this.getStorage(options)         store.setItem(key,value)     },     removeItem(key,options){         let store=this.getStorage(options)         store.removeItem(key)     },     getAll(){},     clear(options){         let store=this.getStorage(options)         store.clear()     },     key(n){},     lenght(){},     has(key){},     forEach(cb){},     deleteAllExpires(){},     // 获取最大存储空间:只有LocalStorage和SessionStorage可以使用这个方法     getMaxSpace(options){         let store=this.getStorage(options)         store.getMaxSpace()     },     // 获取使用了的空间:只有LocalStorage和SessionStorage可以使用这个方法     getUsedSpace(options){         let store=this.getStorage(options)         store.getUsedSpace()     }  } export default storage  // https://segmentfault.com/a/1190000002458488 // 5、遍历localStorage存储的key //     .length 数据总量,例:localStorage.length //     .key(index) 获取key,例:var key=localStorage.key(index);  // 备注:localStorage存数的数据是不能跨浏览器共用的,一个浏览器只能读取各自浏览器的数据,储存空间5M。  // 超时设置 //  function(st, key, value, expires) { //     if (st == 'l') { //         st = window.localStorage; //         expires = expires || 60; //     } else { //         st = window.sessionStorage; //         expires = expires || 5; //     } //     if (typeof value != 'undefined') { //         try { //             return st.setItem(key, JSON.stringify({ //                 data: value, //                 expires: new Date().getTime() + expires * 1000 * 60 //             })); //         } catch (e) {} //     } else { //         var result = JSON.parse(st.getItem(key) || '{}'); //         if (result && new Date().getTime() < result.expires) { //             return result.data; //         } else { //             st.removeItem(key); //             return null; //         } //     } // } 
/*  * localstorage.js  * localstorage的实现  */  // 这个有点奇怪,文件名称叫local.js不能按照js文件解析 export default {     getItem(key){         let item = localStorage.getItem(key)         // 这点要判断是字符串还是对象         let result = /^[{\[].*[}\]]$/g.test(item)         if (result) {             return JSON.parse(item)         } else {             return item         }     },     setItem(key, value){         // 这点要判断是字符串还是对象         if (typeof value == "string") {             localStorage.setItem(key, value)         } else {             let item = JSON.stringify(value)             localStorage.setItem(key, item)         }     },     removeItem(key){         localStorage.removeItem(key)     },     getAll(){},     clear(){         localStorage.clear()     },     key(n){},     forEach(cb){},     has(key){},     deleteAllExpires(){},     // 获取localstorage最大存储容量     getMaxSpace(){         if (!window.localStorage) {             console.log('当前浏览器不支持localStorage!')         }         var test = '0123456789'         var add = function (num) {             num += num             if (num.length == 10240) {                 test = num                 return             }             add(num)         }         add(test)         var sum = test         var show = setInterval(function () {             sum += test             try {                 window.localStorage.removeItem('test')                 window.localStorage.setItem('test', sum)                 console.log(sum.length / 1024 + 'KB')             } catch (e) {                 console.log(sum.length / 1024 + 'KB超出最大限制')                 clearInterval(show)             }         }, 0.1)     },     // 获取使用了的localstorage的空间     getUsedSpace(){         if (!window.localStorage) {             console.log('浏览器不支持localStorage')         }         var size = 0         for (item in window.localStorage) {             if (window.localStorage.hasOwnProperty(item)) {                 size += window.localStorage.getItem(item).length             }         }         console.log('当前localStorage使用容量为' + (size / 1024).toFixed(2) + 'KB')     } } 
/*  * session.js  * sessionstorage的实现  */  export default {     getItem(key){         let item = sessionStorage.getItem(key)         // 这点要判断是字符串还是对象         let result = /^[{\[].*[}\]]$/g.test(item)         if (result) {             return JSON.parse(item)         } else {             return item         }     },     setItem(key, value){         // 这点要判断是字符串还是对象         if (typeof value == "string") {             sessionStorage.setItem(key, value)         } else {             let item = JSON.stringify(value)             sessionStorage.setItem(key, item)         }     },     removeItem(key){         sessionStorage.removeItem(key)     },     getAll(){},     clear(){         sessionStorage.clear()     },     key(n){},     forEach(cb){},     has(key){},     deleteAllExpires(){},     // 获取localstorage最大存储容量     getMaxSpace(){         if (!window.sessionStorage) {             console.log('当前浏览器不支持sessionStorage!')         }         var test = '0123456789'         var add = function (num) {             num += num             if (num.length == 10240) {                 test = num                 return             }             add(num)         }         add(test)         var sum = test         var show = setInterval(function () {             sum += test             try {                 window.sessionStorage.removeItem('test')                 window.sessionStorage.setItem('test', sum)                 console.log(sum.length / 1024 + 'KB')             } catch (e) {                 console.log(sum.length / 1024 + 'KB超出最大限制')                 clearInterval(show)             }         }, 0.1)     },     // 获取使用了的localstorage的空间     getUsedSpace(){         if (!window.sessionStorage) {             console.log('浏览器不支持sessionStorage')         }         var size = 0         for (item in window.sessionStorage) {             if (window.sessionStorage.hasOwnProperty(item)) {                 size += window.sessionStorage.getItem(item).length             }         }         console.log('当前sessionStorage使用容量为' + (size / 1024).toFixed(2) + 'KB')     } } 
/*  * cookies.js  * cooikes的实现,这辈子估计没有时间实现了  */  export default {     getItem(key){},     setItem(key, value){},     removeItem(key){},     getAll(){},     clear(){},     key(n){},     forEach(cb){},     has(key){},     deleteAllExpires(){} } 
/*  * json.js  * json的实现,这辈子估计也没有时间实现了  */ export default {     getItem(key){},     setItem(key, value){},     removeItem(key){},     getAll(){},     clear(){},     key(n){},     forEach(cb){},     has(key){},     deleteAllExpires(){} } 

2.2. 规范命名空间的使用

  • 为了防止key值污染,我们可以合理使用命名空间
    • 我们可以定义命名空间,但是不能把很多数据存储在同一对象里面,这样后面的操作量会太大
    • 比如全局的在global下面
    • 比如各功能系统的加上系统词缀
  • 一个系统的命名空间规范应该提前设计好,否则真正开发起来会有很多人不按照规则使用
  • 全局使用的东西要在README.md文档中体现出来
  • 示例
* localStorage['SGQ.global.userAuthor']:登录的用户信息都在这里,菜单,组织,集团 * localStorage['SGQ.global.systemName']:登录的系统名称 * localStorage['SGQ.vuex.state']:vuex中的state的存储地址,这里面有所有的的东西 * localStorage['SGQ.wms.warehouse']:wms需要的仓库信息   + localStorage['SGQ.wms.warehouse'].permissionId   + localStorage['SGQ.wms.warehouse'].dataResource * localStorage['SGQ.tms.org']:tms需要的网点的信息     + localStorage['SGQ.tms.org'].permissionId     + localStorage['SGQ.tms.org'].orgName 

2.3. storage使用规范

2.3.1. 问题产生的原因

  • 这个问题的产生是因为我们要做权限登录,然后登录的时候一直报存储空间不够的问题,查了原因发现是后端把所有的超管的几千条数据都返回来了,以至于不够用,后来修改了后端接口返回的数据内容解决了这个问题。
  • 但是这次的事给我们带来了几点思考?
    • localstorage和sessionstorage的存储量在不同的浏览器中基本是5M
    • localstorage和sessionstorage的存储是跟着域名来的
      • boss.hivescm.com下localstorage存储是5M
      • b2b.hivescm.com下localstorage存储也是5M
    • 即使这次问题解决了,但是我们应该定一套方案,充分利用一个域名下,localstorage和sessionstorage的共10M空间

2.3.2. storage使用方案

  • 全局使用的东西,共享的东西,永久存储的东西储存在localstorage中
  • 不需要永久存储的东西在使用完毕之后要记得及时清除
  • 如果数据量过大就不要存储在本地了,变为动态获取
  • 可以使用存储量更大的Indexeddb,不过有兼容性问题
  • 可以在实现方案中对要存储到storage中的东西做字数限制
  • 充分合理利用sessionstorage和localstorage的H5特性
    • 例如:列表数据存储在vuex中其实也会存到localstorage
    • 例如:表单校验的一些数据都用sessionstorage

3. 其他

3.1. 延伸扩展

  • 由此可以类推到事件的处理,没用的事件要及时在退出vue组件的时候清理掉
    • 例如:this.bus.$on('aa')要用this.bus.$off('aa')卸载事件

3.2. 字符长短获取

var len = 0 for (var i = 0; i < val.length; i++) {     if (val[i].match(/[^\x00-\xff]/ig) != null) //全角         len += 2 //如果是全角,占用两个字节  如果mysql中某字段是text, 如果设置编码为utf-8,那么一个中文是占3个字节, gbk是两个字节     else         len += 1 //半角占用一个字节 } return len 

4. 参考和引用

5. 特别感谢

  • 公司的小伙伴

6. 免责说明

  • 本文档中的部分内容摘自网上的众多博客,仅作为自己知识的补充和整理,并分享给其他需要的coder,不会用于商用。
  • 因为很多博客的地址看完没有及时做保存,所以很多不会在这里标明出处,非常感谢各位大牛的分享,也希望大家理解。
  • 如果原文作者感觉不适,可以及时联系我shiguoqing999@163.com,我将及时删除争议部分内容

7. 追责声明

  • 如有大段引用超过全文50%的内容,请在文档结尾标明原文出处:龙马行空-石国庆-朱庇特-https://my.oschina.net/u/1416844/blog,否则将视为抄袭,予以法律追究,请各位尊重个人知识产权。
注:本文转载自https://my.oschina.net/u/1416844/blog/1586526,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除。


评论

赞助商