解决vue项目中keep-alive不能缓存多层级路由问题
看了很多文档,都是把嵌套多级路由简化(keep-alive满足二级/一级菜单缓存),菜单数据和路有数据分离开,这种方案解决起来相对复杂一些,下面的方法相对简单一些,我是看了这篇文章,结合自己的项目稍作修改.下边也有自己遇到的问题及解决方法.
需求介绍
自己项目的图片不便粘贴,我还是引用原博主的图片 项目中使用的是3级路由,要实现三级菜单来回跳转保存状态(并且跨二级菜单间的三级菜单页面切换也需要保存状态) 咱们首先想到的是使用keep-alive标签来实现此功能. 在3级router-view的index.vue文件添加keep-alive标签
<template>
<div>
<keep-alive :include="tagNames">
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
</template>
<script>
import { mapGetters } from "vuex";
export default {
name: "Blank",
computed: {
...mapGetters("history", ["tagNames"]),
},
};
</script>
<style lang="scss"></style>
这样只能实现二级菜单内三级菜单页面切换状态可以保存,跨二级菜单间的三级菜单页面切换也需要保存状态是不能实现的.
解决方案
1.把含有3级router-view的文件改为
<template>
<router-view />
</template>
<script>
export default {
name: 'Blank'
}
</script>
2.把之前3级router-view的index.vue中keep-alive展示逻辑,包括:include="tagNames"属性逻辑,都写到2级router-view的vue文件中,在我的项目中此文件为layout文件夹中index.vue,layout为项目中的整体布局文件.代码如下
<transition mode="out-in" name="el-fade-in-linear">
<keep-alive :include="tagNames">
<router-view
v-loading="loadingFlag"
element-loading-text="正在加载中"
id="admin-box"
class="admin-box"
v-if="$route.meta.keepAlive"
></router-view>
</keep-alive>
</transition>
<transition mode="out-in" name="el-fade-in-linear">
<router-view
v-loading="loadingFlag"
element-loading-text="正在加载中"
id="admin-box"
class="admin-box"
v-if="!$route.meta.keepAlive"
></router-view>
</transition>
computed: {
...mapGetters("history", ["tagNames"]),
},
3.在全局路由守卫中加上这段代码:(仅仅只是满足三级菜单缓存)
if (to.matched && to.matched.length > 2) {
for (let i = 0; i < to.matched.length; i++) {
const element = to.matched[i]
if (element.components.default.name === 'Blank') {
to.matched.splice(i, 1)
}
}
}
我按照这种方案实现的时候,出现了两个问题 1.刷新页面后,首次切换页面并没有保存状态,切换后再回来操作才能保存. 2.如果页面中存在面包屑,由于把路由层级splice删掉的一级,导致面包屑层级有问题.
分析
问题1:在页面刷新的时候element.components.default.name是空值,导致to.matched.splice(i, 1)语句不执行.具体什么原因导致的,我没有深究,以后有人发现是啥导致的,可以留言给我. 问题2:由于把路由层级splice删掉的一级,我项目中面包屑正好是用to.matched路由层级遍历生成的所以出现了问题
思路
解决问题1 用数组存放需要保存功能的二级页面名称,只要三级路由结构的路由中含有这些名称,就把三级路由结构中的二级路由手动删除. 解决问题2 在删减层级之前把路由层级保存起来,用于面包屑的展示 直接上代码
router.beforeEach(async(to, from, next) => {
.........
//缓存中保存原有的3级路由title值存入缓存,用于面包屑路径显示(解决问题2)
let matchedRouter = ["controlManagement","...."] //存放需要保存功能的页面名称,这个地方按照你的项目中二级路由页面名称来确定
for (let i = 0; i < to.matched.length; i++) {
const element = to.matched[i]
matchedRouter.push(element.meta.title)
}
sessionStorage.setItem("matchedRouter",JSON.stringify(matchedRouter))
//修复三级路由不能保存状态问题(解决问题1)
if (to.matched && to.matched.length > 2) {
for (let i = 0; i < to.matched.length; i++) {
const element = to.matched[i]
const Index = saveBlankPages.findIndex((item) => {return item === element.name})
if (Index>=0) {
to.matched.splice(i, 1)
}
}
}
..........
面包屑代码
<el-breadcrumb
class="breadcrumb"
separator-class="el-icon-arrow-right"
>
<el-breadcrumb-item
:key="item.path"
v-for="item in matchedRouter.slice(1, matchedRouter.length)"
>{{ item }}</el-breadcrumb-item
>
</el-breadcrumb>
watch: {
$route(){
let matchedRouter = JSON.parse(sessionStorage.getItem("matchedRouter"))
this.matchedRouter = matchedRouter;
}
},
希望对你有帮助
|