当前位置: 首页 > news >正文

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 为字典过期时间
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缓存字典

正常来说&#xff0c;一个vue项目前端需要用到的一些翻译字典对象保存方式一般有多重&#xff0c; 新建js文件方式保存通过vuex方式保存通过sessionStorage保存通过localStorage保存 正常以上几点的保存方式是够用了。 但是&#xff0c;当有字典不能以文件方式保存并且字典量…...

React Redux使用@reduxjs/toolkit的hooks

关于redux的学习过程需要几个官网&#xff0c;有redux官网&#xff0c;React Redux官网和Redux Toolkit的官网。 其中后者的中文没有找到&#xff0c;不过其中的使用在React Redux官网的快速入门中有介绍。 现在一般不使用connect借接口了。 对于借助Redux Toolkit的React Redu…...

Rejetto HFS 服务器存在严重漏洞受到攻击

AhnLab 报告称 &#xff0c;黑客正在针对旧版本的 Rejetto HTTP 文件服务器 (HFS) 注入恶意软件和加密货币挖矿程序。 然而&#xff0c;由于存在错误&#xff0c; Rejetto 警告用户不要使用 2.3 至 2.4 版本。 2.3m 版本在个人、小型团队、教育机构和测试网络文件共享的开发…...

Electron开发 - 如何在主进程Main中让node-fetch使用系统代理

背景 开发过程中&#xff0c;用户设置的系统代理是不同的&#xff0c;比如公司内的服务器&#xff0c;所以就要动态地使用系统代理来访问&#xff0c;但是主进程默认为控制台级别的请求&#xff0c;不走系统代理&#xff0c;除非你指定系统代理配置&#xff0c;这个就就有了这…...

vue2 webpack使用optimization.splitChunks分包,实现按需引入,进行首屏加载优化

optimization.splitChunks的具体功能和配置信息可以去网上自行查阅。 这边简单讲一下他的使用场景、作用、如何使用&#xff1a; 1、没用使用splitChunks进行分包之前&#xff0c;所有模块都揉在一个文件里&#xff0c;那么当这个文件足够大、网速又一般的时候&#xff0c;首…...

深入理解 Docker 容器技术

一、引言 在当今的云计算和软件开发领域&#xff0c;Docker 容器技术已经成为了一项不可或缺的工具。它极大地改变了应用程序的部署和运行方式&#xff0c;为开发者和运维人员带来了诸多便利。 二、Docker 容器是什么&#xff1f; Docker 容器是一种轻量级、可移植、自包含的…...

redis并发、穿透、雪崩

Redis如何实现高并发 首先是单线程模型&#xff1a;redis采用单线程可以避免多线程下切换和竞争的开销&#xff0c;提高cpu的利用率&#xff0c;如果是多核cpu&#xff0c;可以部署多个redis实例。基于内存的数据存储&#xff1a;redis将数据存储在内存中&#xff0c;相比于硬…...

【架构设计】-- ACK 机制

1、ACK 机制的定义 ACK&#xff08;全称&#xff1a;acknowledgement&#xff09; 机制是一种确认机制&#xff0c;起源于TCP报文到达确认&#xff08;ACK&#xff09;机制&#xff08;参考&#xff1a;TCP报文到达确认&#xff08;ACK&#xff09;机制_tcp接收方在收到一个报文…...

这些网络安全知识,请务必牢记!

#网络安全# 随着“互联网”时代的到来&#xff0c;人们的生活变得更加便利&#xff0c;但电信诈骗、信息泄露、恶意软件等也随之而来。面对网络这把双刃剑&#xff0c;如何绷紧思想“安全弦”&#xff0c;正确安全使用网络呢&#xff1f;今天&#xff0c;让我们跟随泰顺网信IP…...

学习笔记——交通安全分析11

目录 前言 当天学习笔记整理 4信控交叉口交通安全分析 结束语 前言 #随着上一轮SPSS学习完成之后&#xff0c;本人又开始了新教材《交通安全分析》的学习 #整理过程不易&#xff0c;喜欢UP就点个免费的关注趴 #本期内容接上一期10笔记 #最近确实太懒了&#xff0c;接受…...

Python 3 编程第一步

Python 3 编程第一步 Python 是一种广泛使用的高级编程语言,以其简洁明了的语法和强大的功能而闻名。Python 3 是该语言的最新版本,它在许多方面对早期的 Python 2 进行了改进和更新。本篇文章将作为 Python 3 编程的入门指南,带你迈出编程的第一步。 Python 3 的安装 首…...

【eMTC】eMTC 窄带以及带宽的关系

1 概述 eMTC 传输进行通信时&#xff0c;一般采用1.4M带宽&#xff0c;在和LTE小区联合部署时&#xff0c;需要将LTE的带宽分割成以1.4M带宽为粒度的单位&#xff0c;这个单位在协议上叫做窄带。 2 窄带定义 3 参考文献 36.211...

【MySQL】mysqldumpslow工具 -- 总结慢查询日志文件

1. 作用 在平时使用MySQL数据库时&#xff0c;经常进行查询操作&#xff0c;有些查询语句执行的时间非常长&#xff0c;当执行时间超过设定的阈值时&#xff0c;我们称这个查询为慢查询&#xff0c;慢查询的相关信息通常需要用日志记录下来称为慢查询日志&#xff0c;mysqldum…...

【mindspore进阶】02-ResNet50迁移学习

Mindspore 应用&#xff08;2&#xff09;ResNet50迁移学习 在实际应用场景中&#xff0c;由于训练数据集不足&#xff0c;所以很少有人会从头开始训练整个网络。普遍的做法是&#xff0c;在一个非常大的基础数据集上训练得到一个预训练模型&#xff0c;然后使用该模型来初始化…...

智能决策的艺术:揭秘决策树的奇妙原理与实战应用

引言 决策树&#xff08;Decision Tree&#xff09;是一种常用的监督学习算法&#xff0c;适用于分类和回归任务。它通过学习数据中的规则生成树状模型&#xff0c;从而做出预测决策。决策树因其易于理解和解释、无需大量数据预处理等优点&#xff0c;广泛应用于各种机器学习任…...

基于AOP的数据字典实现:实现前端下拉框的可配置更新

作者&#xff1a;后端小肥肠 创作不易&#xff0c;未经允许严禁转载。 目录 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对应版本参考&#xff1a;https://www.rabbitmq.com/which-erlang.html 2. 安装erlang 官网&#xff1a;https://www.erlang.org/downloads GitHub: https://github.com/rabbitmq/erlang-rpm/releases 2.1 安装依赖&#xff1a; yum -y install gcc glib…...

9、Redis 高级数据结构 HyperLogLog 和事务

1. HyperLogLog 简介 HyperLogLog 是一种用于基数估计的概率数据结构。它并不是一种新的数据结构&#xff0c;而是 Redis 中的一种字符串类型。HyperLogLog 的主要优点是能够利用极少的内存空间完成对独立总数的统计&#xff0c;适用于统计大量数据的独立元素数量&#xff0c…...

MyBatis(30)如何在 MyBatis 中使用 XML 和注解混合配置方式

在MyBatis中&#xff0c;你可以灵活地选择XML配置方式、注解方式&#xff0c;或者将这两种方式混合使用来配置你的映射器&#xff08;Mapper&#xff09;。使用混合配置方式&#xff0c;你可以结合两者的优势&#xff0c;例如&#xff0c;利用XML配置复杂查询和动态SQL&#xf…...

强化学习与控制模型结合例子

强化学习与模型控制结合 强化学习(Reinforcement Learning, RL)与控制模型结合,可以通过整合传统控制理论和现代RL算法,利用控制模型提供的动态信息和稳定性保障,同时利用RL的学习能力优化控制策略。这种结合的方式被称为模型辅助强化学习(Model-Assisted Reinforcement…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...

macOS 终端智能代理检测

&#x1f9e0; 终端智能代理检测&#xff1a;自动判断是否需要设置代理访问 GitHub 在开发中&#xff0c;使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新&#xff0c;例如&#xff1a; fatal: unable to access https://github.com/ohmyzsh/oh…...

前端高频面试题2:浏览器/计算机网络

本专栏相关链接 前端高频面试题1&#xff1a;HTML/CSS 前端高频面试题2&#xff1a;浏览器/计算机网络 前端高频面试题3&#xff1a;JavaScript 1.什么是强缓存、协商缓存&#xff1f; 强缓存&#xff1a; 当浏览器请求资源时&#xff0c;首先检查本地缓存是否命中。如果命…...