vue前端通过sessionStorage缓存字典
正常来说,一个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为字典过期时间
export default function (dictKeys = []) {let _isBeforeRouteEnterDictQuery = falsereturn {data() {return {m_dictsFin: false,m_dicts: {}}},provide: function () {return {m_dicts: this.m_dicts}},methods: {getSessionStorageSize(){let obj = ''let size = 0if(!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 = 4608if(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 = 4608if(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.dictDatassessionStorage.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 = truenext(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_TIMEOUTsessionStorage.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_TIMEOUTsessionStorage.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_TIMEOUTsessionStorage.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_TIMEOUTsessionStorage.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) returnif (!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_TIMEOUTsessionStorage.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_TIMEOUTsessionStorage.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_TIMEOUTsessionStorage.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_TIMEOUTsessionStorage.setItem('SESSION_TIMEOUT', timing)//调用接口if(dictKeys && dictKeys.length > 0){await queryBatchCode(dictKeys, { isNoLoading: true }).then(res => {this.setPageConfig(res)})}}}}}}}
}
在具体页面中使用
import pageDictMixin from '@/mixin/page-dict-mixin'mixins: [pageDictMixin(['DICT_YES_NO'])],
html部分代码
<el-optionv-for="item in m_dicts.DICT_YES_NO" :key="item.dataValue":label="item.dataLabel" :value="item.dataValue" />
相关文章:
vue前端通过sessionStorage缓存字典
正常来说,一个vue项目前端需要用到的一些翻译字典对象保存方式一般有多重, 新建js文件方式保存通过vuex方式保存通过sessionStorage保存通过localStorage保存 正常以上几点的保存方式是够用了。 但是,当有字典不能以文件方式保存并且字典量…...
React Redux使用@reduxjs/toolkit的hooks
关于redux的学习过程需要几个官网,有redux官网,React Redux官网和Redux Toolkit的官网。 其中后者的中文没有找到,不过其中的使用在React Redux官网的快速入门中有介绍。 现在一般不使用connect借接口了。 对于借助Redux Toolkit的React Redu…...
Rejetto HFS 服务器存在严重漏洞受到攻击
AhnLab 报告称 ,黑客正在针对旧版本的 Rejetto HTTP 文件服务器 (HFS) 注入恶意软件和加密货币挖矿程序。 然而,由于存在错误, Rejetto 警告用户不要使用 2.3 至 2.4 版本。 2.3m 版本在个人、小型团队、教育机构和测试网络文件共享的开发…...
Electron开发 - 如何在主进程Main中让node-fetch使用系统代理
背景 开发过程中,用户设置的系统代理是不同的,比如公司内的服务器,所以就要动态地使用系统代理来访问,但是主进程默认为控制台级别的请求,不走系统代理,除非你指定系统代理配置,这个就就有了这…...
vue2 webpack使用optimization.splitChunks分包,实现按需引入,进行首屏加载优化
optimization.splitChunks的具体功能和配置信息可以去网上自行查阅。 这边简单讲一下他的使用场景、作用、如何使用: 1、没用使用splitChunks进行分包之前,所有模块都揉在一个文件里,那么当这个文件足够大、网速又一般的时候,首…...
深入理解 Docker 容器技术
一、引言 在当今的云计算和软件开发领域,Docker 容器技术已经成为了一项不可或缺的工具。它极大地改变了应用程序的部署和运行方式,为开发者和运维人员带来了诸多便利。 二、Docker 容器是什么? Docker 容器是一种轻量级、可移植、自包含的…...
redis并发、穿透、雪崩
Redis如何实现高并发 首先是单线程模型:redis采用单线程可以避免多线程下切换和竞争的开销,提高cpu的利用率,如果是多核cpu,可以部署多个redis实例。基于内存的数据存储:redis将数据存储在内存中,相比于硬…...
【架构设计】-- ACK 机制
1、ACK 机制的定义 ACK(全称:acknowledgement) 机制是一种确认机制,起源于TCP报文到达确认(ACK)机制(参考:TCP报文到达确认(ACK)机制_tcp接收方在收到一个报文…...
这些网络安全知识,请务必牢记!
#网络安全# 随着“互联网”时代的到来,人们的生活变得更加便利,但电信诈骗、信息泄露、恶意软件等也随之而来。面对网络这把双刃剑,如何绷紧思想“安全弦”,正确安全使用网络呢?今天,让我们跟随泰顺网信IP…...
学习笔记——交通安全分析11
目录 前言 当天学习笔记整理 4信控交叉口交通安全分析 结束语 前言 #随着上一轮SPSS学习完成之后,本人又开始了新教材《交通安全分析》的学习 #整理过程不易,喜欢UP就点个免费的关注趴 #本期内容接上一期10笔记 #最近确实太懒了,接受…...
Python 3 编程第一步
Python 3 编程第一步 Python 是一种广泛使用的高级编程语言,以其简洁明了的语法和强大的功能而闻名。Python 3 是该语言的最新版本,它在许多方面对早期的 Python 2 进行了改进和更新。本篇文章将作为 Python 3 编程的入门指南,带你迈出编程的第一步。 Python 3 的安装 首…...
【eMTC】eMTC 窄带以及带宽的关系
1 概述 eMTC 传输进行通信时,一般采用1.4M带宽,在和LTE小区联合部署时,需要将LTE的带宽分割成以1.4M带宽为粒度的单位,这个单位在协议上叫做窄带。 2 窄带定义 3 参考文献 36.211...
【MySQL】mysqldumpslow工具 -- 总结慢查询日志文件
1. 作用 在平时使用MySQL数据库时,经常进行查询操作,有些查询语句执行的时间非常长,当执行时间超过设定的阈值时,我们称这个查询为慢查询,慢查询的相关信息通常需要用日志记录下来称为慢查询日志,mysqldum…...
【mindspore进阶】02-ResNet50迁移学习
Mindspore 应用(2)ResNet50迁移学习 在实际应用场景中,由于训练数据集不足,所以很少有人会从头开始训练整个网络。普遍的做法是,在一个非常大的基础数据集上训练得到一个预训练模型,然后使用该模型来初始化…...
智能决策的艺术:揭秘决策树的奇妙原理与实战应用
引言 决策树(Decision Tree)是一种常用的监督学习算法,适用于分类和回归任务。它通过学习数据中的规则生成树状模型,从而做出预测决策。决策树因其易于理解和解释、无需大量数据预处理等优点,广泛应用于各种机器学习任…...
基于AOP的数据字典实现:实现前端下拉框的可配置更新
作者:后端小肥肠 创作不易,未经允许严禁转载。 目录 1. 前言 2. 数据字典 2.1. 数据字典简介 2.2. 数据字典如何管理各模块的下拉框 3. 数据字典核心内容解读 3.1. 表结构 3.2. 核心代码 3.2.1. 根据实体类名称获取下属数据字典 3.2.2. 数据字…...
基于CentOS Stream 9平台搭建RabbitMQ3.13.4以及开机自启
1. erlang与RabbitMQ对应版本参考:https://www.rabbitmq.com/which-erlang.html 2. 安装erlang 官网:https://www.erlang.org/downloads GitHub: https://github.com/rabbitmq/erlang-rpm/releases 2.1 安装依赖: yum -y install gcc glib…...
9、Redis 高级数据结构 HyperLogLog 和事务
1. HyperLogLog 简介 HyperLogLog 是一种用于基数估计的概率数据结构。它并不是一种新的数据结构,而是 Redis 中的一种字符串类型。HyperLogLog 的主要优点是能够利用极少的内存空间完成对独立总数的统计,适用于统计大量数据的独立元素数量,…...
MyBatis(30)如何在 MyBatis 中使用 XML 和注解混合配置方式
在MyBatis中,你可以灵活地选择XML配置方式、注解方式,或者将这两种方式混合使用来配置你的映射器(Mapper)。使用混合配置方式,你可以结合两者的优势,例如,利用XML配置复杂查询和动态SQL…...
强化学习与控制模型结合例子
强化学习与模型控制结合 强化学习(Reinforcement Learning, RL)与控制模型结合,可以通过整合传统控制理论和现代RL算法,利用控制模型提供的动态信息和稳定性保障,同时利用RL的学习能力优化控制策略。这种结合的方式被称为模型辅助强化学习(Model-Assisted Reinforcement…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
