问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

vue多级路由缓存(keep-alive)失效的解决方案

发布网友 发布时间:2024-09-15 08:03

我来回答

1个回答

热心网友 时间:2024-10-01 19:53

最近在开发一个基于Vue3的后台管理系统,整个项目结构参考了vue-element-plus-admin(简称admin),在处理页面缓存方面,它使用了keep-alive结合router-view实现,这也是大多后台系统的方向。由于admin的router是一个扁平结构,故不存在缓存失效问题。而我的系统的router是个树结构,涉及多层router-view嵌套,这样admin中简单的实现就满足不了我的需求了。

如何解决多级路由缓存失效问题?是本文讨论的重点,如果你也有同我一样的烦恼,不妨读读本文?。

小编简化系统由这几个部分组成:

基础布局:Layout.vue

路由配置:router.js

路由页面:Home.vue、About.vue、Theme1.vue、Theme2-1.vue、Theme3、NestRouterView.vue

方案一(树结构转扁平结构)

项目中的routes管理如下,很经典的树结构。根节点是一个基础布局,所有页面都基于这个布局展示。二级路由上,借助了router-view组件去承载子路由。我们给像NestRouterView.vue此类功能组件统称为『中间件』。

constviews={path:"/",component:()=>import("@/views/Layout.vue"),children:[{name:"Home",path:"",component:()=>import("@/views/Home.vue"),meta:{title:"首页",keepAlive:false}},{name:"About",path:"about",component:()=>import("@/views/About.vue"),meta:{title:"关于",keepAlive:true}},{path:"",component:()=>import("@/views/NestRouterView.vue"),children:[{name:"Theme1",path:"theme/1",component:()=>import("@/views/Theme1.vue"),meta:{title:"主题1",keepAlive:true}},{name:"Theme3",path:"theme/3",component:()=>import("@/views/Theme3.vue"),meta:{title:"主题3",keepAlive:false}},{path:"",component:()=>import("@/views/NestRouterView.vue"),children:[{name:"Theme2-1",path:"theme/2/1",component:()=>import("@/views/Theme2-1.vue"),meta:{title:"主题2-1",keepAlive:true}}]}]}]}<template><router-view/></template><script>exportdefault{name:'NestRouterView'}</script>

实际上是否是多级路由对于项目或者业务上来讲一点都不影响,只是界面显示需要,让用户能更快的找到自己需要的功能页面而已。这样的话,显示的路由保留多级的,实际上router维护成一级,将显示菜单和业务router分离开。放弃原有树结构,保持router扁平化,我们就得到了以下的routes,不存在复杂嵌套,也不构建多余的『中间件』组件。

constviews={path:"/",component:()=>import("@/views/Layout.vue"),children:[{name:"Home",path:"",component:()=>import("@/views/Home.vue"),meta:{title:"首页",keepAlive:false}},......{name:"Theme1",path:"theme/1",component:()=>import("@/views/Theme1.vue"),meta:{title:"主题1",keepAlive:true}},......{name:"Theme2-1",path:"theme/2/1",component:()=>import("@/views/Theme2-1.vue"),meta:{title:"主题2-1",keepAlive:true}}]}

有人说我这项目里有几十、上百条路由配置,让我手动打平,我这一天都别干活了。好办!既然『中间件』只是承载子路由功能,那我们就可以在扁平化过程中不考虑它。

constformatRouter=(routes,newRoutes=[])=>{routes.forEach((item)=>{if(item.children&&item.children.length>0){formatRouter(item.children,newRoutes);}else{newRoutes.push(item);}});returnnewRoutes;};views.children=formatRouter(views.children);

最终效果如下,除了首页和主题3页面都进行了缓存。

完整代码

方案二

方案一的实现直接明了,却存在很多局限性。特别是『中间件』文件(NestRouterView.vue),要是承载着业务功能,那就不能这么简单粗暴解决了。接下来我们来看看方案二的解法。

方案二的实现得力于3个函数:

findRouterWith

getFileNameByFunContext

getCachesByRoutes

findRouterWith以『中间件』组件名作为查询条件来获取所有以其作为载体的页面。

//找到以组件名name作为“中间件”的所有路由exportconstfindRouterWith=(name)=>{constfn=(routes,newRoutes=[])=>{routes.forEach((item)=>{if(item.children&&item.children.length>0){if(getFileNameByFunContext(item.component.toString())===name){newRoutes.push(item.children);}fn(item.children,newRoutes);}});returnnewRoutes.flat(Infinity);};returnfn;};

由于在router.js中配置的component是一个箭头函数,我们无法直接获取『中间件』组件名,故采用通过函数内容来获取组件名。

{path:"/",component:()=>import("@/views/NestRouterView.vue")}

component.toString()

functioncomponent(){return__webpack_require__.e(/*!import()*/4).then(__webpack_require__.bind(null,/*!@/views/NestRouterView.vue*/"./src/views/NestRouterView.vue"));}

通过观察,我们发现好提取的组件名位于双引号之间,这样我们就可以先通过提取组件路径,然后再匹配文件名。如果你有更好的写法也可以在评论区告诉我。

//通过函数内容获取文件名exportconstgetFileNameByFunContext=(str)=>{const[file=""]=str.match(/".+"/);returnfile.replace(/(.*\/)*([^.]+).*/gi,"$2");};

getCachesByRoutes函数以路由数组入参,返回需进行缓存的一个数组。

函数先是定义了一个children变量来存储『中间件』,接着过滤掉路由中所有含有子集(借助了『中间件』)或是不需要缓存的项,将含有子集项的值存储于children中,最后的返回值是由已过滤路由和『中间件』集组成。

//获取需进行缓存的页面exportconstgetCachesByRoutes=(routes=[])=>{constchildren=[];constcaches=routes.filter((o)=>{//有children说明进行了路由嵌套,需记录“中间件”if(o.children){children.push(o.component);}//过滤掉“中间件”和不需要缓存的组件return!o.children&&o.meta.keepAlive;}).map((o)=>o.name);if(children.length>0){//路由嵌套的组件也需includechildren.forEach((fun)=>{caches.push(getFileNameByFunContext(fun.toString()));});}return[...newSet(caches)];//排重};

以『中间件』(NestRouterView.vue)为例,此时的NestRouterView不仅仅是容器,还承载功能。首先,我们看router.js文件,routes比原来多了层嵌套,情况也就更复杂;接着findRouterWith获取以NestRouterView为父组件的所有路由,最后通过getCachesByRoutes来获取需在本组件进行缓存的数组。

router.js

constroutes=[{path:"/",component:()=>import("@/views/Layout.vue"),children:[......//同上{path:"",component:()=>import("@/views/NestRouterView.vue"),children:[......//同上{path:"",component:()=>import("@/views/NestRouterView.vue"),children:[{name:"Theme2-1",path:"theme/2/1",component:()=>import("@/views/Theme2-1.vue"),meta:{title:"主题2-1",keepAlive:true}}]}]}]}];

NestRouterView.vue

<template><router-view/></template><script>exportdefault{name:'NestRouterView'}</script>0

最终效果如下,除了首页和主题3页面都进行了缓存。但有个地方比较怪异,就是主题2-1页面出现了两个【返回】功能。那是因为NestRouterView嵌套所致,你可以通过设置prop的方式来达到页面统一。

<template><router-view/></template><script>exportdefault{name:'NestRouterView'}</script>1<template><router-view/></template><script>exportdefault{name:'NestRouterView'}</script>2

完整代码

小结

方案一是目前互联网中最常见的解法,个人觉得还是存在较大的局限性。方案二是小编在项目开发过程中摸索出的解法,可扩展行强。强推!!!若你还有更好的方案,可分享于我。

若你在使用keep-alive中有疑惑,可移步姊妹篇《看keep-alive如何在项目中失效》

看过姊妹篇的朋友可能记得小编说过,vue-router的name属性是用于路由跳转,不是用于keep-alive,但在本文的方法却取了vue-router的name用于include中。这是因为小编统一了组件和vue-router的name,更有利于项目的维护。

本文首发掘金平台,来源个人博客

原文:https://juejin.cn/post/7099355285172518920
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
什么叫补按揭 后按揭贷款什么意思 买房者续按揭有什么危害 加按揭是什么意思 八月中国最凉快的地方 八月份哪里最凉快,去哪旅游好?美丽的地方 乱字同韵字是什么意思 华硕笔记本电脑触摸板怎么开笔记本电脑触摸板怎么开启和关闭_百度知 ... 陕西职务侵占案立案准则 结婚后我的恋情维系了十年,怎么做到的? 这个金属东西叫什么?类似扣子。 玩具是孩子生活中的伙伴,应该如何为孩子选择“安全”的毛绒玩具呢?_百 ... 金属扣子会被检测出来吗? 我今天中午不小心将一颗衣服的纽扣咽进肚子里,请问该怎么办_百度... 西海岸对国安 青岛西海岸主教练是谁 “四阶魔方单边翻棱”图解 百雀羚哪个系列的护肤品适合中年女性? 百雀羚有哪些护肤品值得入手? 悠久之翼第一季结局 宁夏科技馆的旧馆 海钓钓大鱼用什么钩比较好 海钓如何能够钓到大鱼 海钓大鱼的重要技巧 乳液聚合中乳化剂的种类和作用分别是什么? 引发剂发展概况 已婚男人梦到自己结婚是什么意思? u盘插入电脑出现问题怎么修复? u盘出现问题了怎么修复? 电脑修复U盘的办法有哪些? 每日开发记录2023072402,vue使用keep-alive实现页面前进刷新,后退缓存... 故意伤害法院主持调解可以吗? 法院调解时,证人需要到场吗 法院调解的概念是什么? 宙有哪些词语 水浒传108名英雄有三个女子的名字是 碧盛名鹤洗发水好吗 碧丽芙洗发水怎么样 山东理工大学是985,还是211大学 34寸显示器长宽多少16:9 高中物理x到底表示什么? 3秒将CAD图纸表格转换为EXCEL表格,真好用啊! 海尔全自动洗衣机为什么不能脱水了?! 怎么在手机上打汉字标注拼音? 微信聊天字上面怎么打拼音 喉咙发炎吃什么菜好 扁桃体发炎吃什么菜好 嗓子疼吃什么菜 小爱同学能连接小米智能家庭吗? 英语单词q接龙