vue前端通过sessionStorage缓存字典

正常来说,一个vue项目前端需要用到的一些翻译字典对象保存方式一般有多重,

  1. 新建js文件方式保存
  2. 通过vuex方式保存
  3. 通过sessionStorage保存
  4. 通过localStorage保存

正常以上几点的保存方式是够用了。

但是,当有字典不能以文件方式保存并且字典量很多很大时候,要考虑的事情就多了。

首选最新考虑存储的地方是vuex跟session,安全性会相对高一些,其次就需要考虑如果量大的问题。当字典数据量超过5MB的话,那session就有些难受了。而vuex持久存储也是需要先存Storage中再取回到内存中用。那么怎么比较好解决这个量大且不能以文件存储方式呢。

思路:

(字典都是从后端调接口获取)

  1. 还是通过session方式储存,额外有的看需求要不要再存储到vuex中
  2. 给session增加存储过期时间
  3. 给session增加存储量是否接近5MB存储上限判断
  4. 字典通过后端调接口获取
    4.1 获取地方 1.通过路由跳转时beforeRouteEnter回调中调用跟判断
    4.2 获取地方 2.通过页面created 回调中调用跟判断(有的是弹框子组件或者form表单并没有进行路由跳转)
  5. 由于基本每个菜单页面都要使用到字典,所以考虑通过混入mixin方式
  6. #由于字典一般用于选项跟翻译,所以需要考虑是否使用 async/await方式来同步代码,确保字典数据先取到再进入页面。是否使用各有利弊。

混入代码:

  1. window.g.SESSION_TIMEOUT 是定义全局变量,可配置
  2. DICE_KEYS 是存储字典key的数组
  3. SESSION_TIMEOUT 为字典过期时间
javascript 复制代码
export default function (dictKeys = []) {
  let _isBeforeRouteEnterDictQuery = false
  return {
    data() {
      return {
        m_dictsFin: false,
        m_dicts: {}
      }
    },

    provide: function () {
      return {
        m_dicts: this.m_dicts
      }
    },
    methods: {
      getSessionStorageSize(){
        let obj = ''
        let size = 0
        if(!window.sessionStorage){
          try {
            throw Error('浏览器不支持sessionStorage')
          } catch (error) {
            console.log(error)
          }
        }else {
          obj = window.sessionStorage
        }
        if(obj !== ''){
          for(item in obj){
            if(obj.hasOwnProperty(item)){
              size += obj.getItem(item).length
            }
          }
        }
        let val = (size/1024).toFixed(2) //单位KB 5MB = 1024*5 = 5120kB
        // 1024 * 4.5 = 4608
        if(val > 4608){ //如果存储大小超过4.5MB则需清空KEY重新获取过
          return true
        }else {
          return false
        }
      },
      //如果上面一个获取方法不可用,可以考虑使用这个方法替换
      estimateSessionStorageSize() {
        let totalSize = 0;
        // 遍历 sessionStorage 中的每个项
        for (let i = 0; i < sessionStorage.length; i++) {
            const key = sessionStorage.key(i)
            const value = sessionStorage.getItem(key)
            // 估算每个项的大小(这里简单估算每个字符占2个字节)
            // 注意:这只是一个非常粗略的估算
            const size = (new Blob([key + value])).size
            // 累加大小
            totalSize += size
        }
        let val = (totalSize/1024).toFixed(2) //单位KB 5MB = 1024*5 = 5120kB
        // 1024 * 4.5 = 4608
        if(val > 4608){ //如果存储大小超过4.5MB则需清空KEY重新获取过
          return true
        }else {
          return false
        }
      },
      setPageConfig(res,vm){
        const list = res?.data?.data || []
        store.dispatch('dynamicDicts', list)
        const pathAllDict = {}
        if (list && list.length > 0) {
          const sessionName = []
          list.forEach(e => {
            if (e) {
              if(vm){
                vm.$set(vm.m_dicts, e.dictCode, e.dictDatas)
              }else {
                this.$set(this.m_dicts, e.dictCode, e.dictDatas)
              }
              sessionName.push(e.dictCode)
              pathAllDict[e.dictCode] = e.dictDatas
              sessionStorage.setItem(e.dictCode, JSON.stringify(e.dictDatas))
            }
          })
          store.commit('SET_DICT_DATA', pathAllDict)
          let currentSessionKey = sessionStorage.getItem('DICE_KEYS') ? sessionStorage.getItem('DICE_KEYS').split(',') : []
          console.log('setPageConfig',currentSessionKey,sessionName)
          console.log('DICE_KEYS',[...new Set([...currentSessionKey,...sessionName])])
          sessionStorage.setItem('DICE_KEYS', [...new Set([...currentSessionKey,...sessionName])])
          if(vm){
            vm.$nextTick(() => {
              vm.m_dictsFin = true
            })
          }else {
            this.m_dictsFin = true
          }
        }
      }
    },

     beforeRouteEnter(to, from, next) {
      _isBeforeRouteEnterDictQuery = true
      next(async vm => {
        const date = new Date().getTime()
        let DICE_KEYS = sessionStorage.getItem('DICE_KEYS') || []
        if(!DICE_KEYS || DICE_KEYS.length === 0){ //没存字典或者已全删除
          //重新设置过期时间
          let timing = date + 1000 * 60 * window.g.SESSION_TIMEOUT
          sessionStorage.setItem('SESSION_TIMEOUT', timing)
          //调用接口
          if(dictKeys && dictKeys.length > 0){
              await queryBatchCode(dictKeys, { isNoLoading: true }).then(res => {
                vm.setPageConfig(res,vm)
              }).catch(e => {
                console.log('catch')
                next()
              })
          }
        }else {
          //获取过期时间
          let timeout = sessionStorage.getItem('SESSION_TIMEOUT')
          const preSessionS = DICE_KEYS.length>0 ? DICE_KEYS.split(',') : [] //转为数组
          if(vm.getSessionStorageSize()){
            preSessionS.forEach(item => {
              sessionStorage.removeItem(item)//清除所有字典
            })
            sessionStorage.setItem('DICE_KEYS',[])
            //重新设置过期时间
            let timing = date + 1000 * 60 * window.g.SESSION_TIMEOUT
            sessionStorage.setItem('SESSION_TIMEOUT', timing)
            //调用接口
            if(dictKeys && dictKeys.length > 0){
                await queryBatchCode(dictKeys, { isNoLoading: true }).then(res => {
                  vm.setPageConfig(res,vm)
                }).catch(e => {
                  console.log('catch')
                  next()
                })
            }
          }else {
            if(timeout){
              if(timeout - date <= 0){ //已过期
                preSessionS.forEach(item => {
                  sessionStorage.removeItem(item)//清除所有字典
                })
                sessionStorage.setItem('DICE_KEYS',[])
                //重新设置过期时间
                let timing = date + 1000 * 60 * window.g.SESSION_TIMEOUT
                sessionStorage.setItem('SESSION_TIMEOUT', timing)
                if(dictKeys && dictKeys.length > 0){
                  await queryBatchCode(dictKeys, { isNoLoading: true }).then(res => {
                    vm.setPageConfig(res,vm)
                  }).catch(e => {
                    console.log('catch')
                    next()
                  })
                }
              } else {
                //将已存在于session重的key,挂载到m_dicts对象重
                let sessionKeyList = dictKeys.filter(item => preSessionS.includes(item))
                sessionKeyList.forEach(e => {
                  if (e) {
                    vm.$set(vm.m_dicts, e, JSON.parse(sessionStorage.getItem(e)))
                  }
                })
                //当前dictKeys匹配session中不存在的key去请求
                let reqKeyList = dictKeys.filter(item => !preSessionS.includes(item))
                if(reqKeyList.length >0){
                  await queryBatchCode(reqKeyList, { isNoLoading: true }).then(res => {
                    vm.setPageConfig(res,vm)
                  }).catch(e => {
                    console.log('catch')
                    next()
                  })
                }
              }
            }else {
              //重新设置过期时间
              let timing = date + 1000 * 60 * window.g.SESSION_TIMEOUT
              sessionStorage.setItem('SESSION_TIMEOUT', timing)
              //调用接口
              if(dictKeys && dictKeys.length > 0){
                await queryBatchCode(dictKeys, { isNoLoading: true }).then(res => {
                  vm.setPageConfig(res,vm)
                }).catch(e => {
                  console.log('catch')
                  next()
                })
              }
            }
          }
        }
      })
    },

    // 有些非路由跳转触发的组件, 在 created 中调用
    async created() {
      if (_isBeforeRouteEnterDictQuery) return
      if (!this.m_dictsFin) {
        const date = new Date().getTime()
        let DICE_KEYS = sessionStorage.getItem('DICE_KEYS') || []
        if(!DICE_KEYS || DICE_KEYS.length === 0){ //没存字典或者已全删除
          //重新设置过期时间
          let timing = date + 1000 * 60 * window.g.SESSION_TIMEOUT
          sessionStorage.setItem('SESSION_TIMEOUT', timing)
          //调用接口
          if(dictKeys && dictKeys.length > 0){
            await queryBatchCode(dictKeys, { isNoLoading: true }).then(res => {
              this.setPageConfig(res)
            })
          }
        }else {
          //获取过期时间
          let timeout = sessionStorage.getItem('SESSION_TIMEOUT')
          const preSessionS = DICE_KEYS.length>0 ? DICE_KEYS.split(',') : [] //转为数组
          if(this.getSessionStorageSize()){
            preSessionS.forEach(item => {
              sessionStorage.removeItem(item)//清除所有字典
            })
            sessionStorage.setItem('DICE_KEYS',[])
            //重新设置过期时间
            let timing = date + 1000 * 60 * window.g.SESSION_TIMEOUT
            sessionStorage.setItem('SESSION_TIMEOUT', timing)
            //调用接口
            if(dictKeys && dictKeys.length > 0){
                await queryBatchCode(dictKeys, { isNoLoading: true }).then(res => {
                  this.setPageConfig(res)
                })
            }
          }else {
            if(timeout){
              if(timeout - date <= 0){ //已过期
                  preSessionS.forEach(item => {
                    sessionStorage.removeItem(item)//清除所有字典
                  })
                  sessionStorage.setItem('DICE_KEYS',[])
                  //重新设置过期时间
                  let timing = date + 1000 * 60 * window.g.SESSION_TIMEOUT
                  sessionStorage.setItem('SESSION_TIMEOUT', timing)
                  if(dictKeys && dictKeys.length > 0){
                    await queryBatchCode(dictKeys, { isNoLoading: true }).then(res => {
                      this.setPageConfig(res)
                    })
                  }
              } else {
                //将已存在于session重的key,挂载到m_dicts对象重
                let sessionKeyList = dictKeys.filter(item => preSessionS.includes(item))
                sessionKeyList.forEach(e => {
                  if (e) {
                    this.$set(this.m_dicts, e, JSON.parse(sessionStorage.getItem(e)))
                  }
                })
                //当前dictKeys匹配session中不存在的key去请求
                let reqKeyList = dictKeys.filter(item => !preSessionS.includes(item))
                if(reqKeyList.length >0){
                  await queryBatchCode(reqKeyList, { isNoLoading: true }).then(res => {
                    this.setPageConfig(res)
                  })
                }
              }
            }else {
              let timing = date + 1000 * 60 * window.g.SESSION_TIMEOUT
              sessionStorage.setItem('SESSION_TIMEOUT', timing)
              //调用接口
              if(dictKeys && dictKeys.length > 0){
                await queryBatchCode(dictKeys, { isNoLoading: true }).then(res => {
                  this.setPageConfig(res)
                })
              }
            }
          }
        }
      }
    }
  }
}

在具体页面中使用

javascript 复制代码
import pageDictMixin from '@/mixin/page-dict-mixin'

mixins: [
    pageDictMixin([
      'DICT_YES_NO'
    ])
  ],

html部分代码

html 复制代码
<el-option
                  v-for="item in m_dicts.DICT_YES_NO" :key="item.dataValue"
                  :label="item.dataLabel" :value="item.dataValue" />
相关推荐
迷途小码农零零发几秒前
解锁微前端的优秀库
前端
王解1 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
我不当帕鲁谁当帕鲁1 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂1 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐2 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
jerry6094 小时前
7天用Go从零实现分布式缓存GeeCache(改进)(未完待续)
分布式·缓存·golang
毋若成4 小时前
前端三大组件之CSS,三大选择器,游戏网页仿写
前端·css
红中马喽4 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
Black蜡笔小新5 小时前
网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
前端·javascript·html
秦jh_6 小时前
【Linux】多线程(概念,控制)
linux·运维·前端