正常来说,一个vue项目前端需要用到的一些翻译字典对象保存方式一般有多重,
- 新建js文件方式保存
- 通过vuex方式保存
- 通过sessionStorage保存
- 通过localStorage保存
正常以上几点的保存方式是够用了。
但是,当有字典不能以文件方式保存并且字典量很多很大时候,要考虑的事情就多了。
首选最新考虑存储的地方是vuex跟session,安全性会相对高一些,其次就需要考虑如果量大的问题。当字典数据量超过5MB的话,那session就有些难受了。而vuex持久存储也是需要先存Storage中再取回到内存中用。那么怎么比较好解决这个量大且不能以文件存储方式呢。
思路:
(字典都是从后端调接口获取)
- 还是通过session方式储存,额外有的看需求要不要再存储到vuex中
- 给session增加存储过期时间
- 给session增加存储量是否接近5MB存储上限判断
- 字典通过后端调接口获取
4.1 获取地方 1.通过路由跳转时beforeRouteEnter
回调中调用跟判断
4.2 获取地方 2.通过页面created
回调中调用跟判断(有的是弹框子组件或者form表单并没有进行路由跳转) - 由于基本每个菜单页面都要使用到字典,所以考虑通过混入
mixin
方式 - #由于字典一般用于选项跟翻译,所以需要考虑是否使用
async/await
方式来同步代码,确保字典数据先取到再进入页面。是否使用各有利弊。
混入代码:
window.g.SESSION_TIMEOUT
是定义全局变量,可配置DICE_KEYS
是存储字典key的数组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" />