vue-element-admin
vue-element-admin copied to clipboard
三级菜单缓存问题解决方案
2022/07/08更新了写法(往下翻翻),原内容已过时
以下为原内容
2018年就有相关提问,最后似乎作者似乎也没有把这个问题解决?好像也不怎么更新维护了 最近折腾这个问题提供一个方案: 1.src/store/modules/tagsView.js中修改ADD_CACHED_VIEW方法,将二级菜单加入缓存
ADD_CACHED_VIEW: (state, view) => {
if (state.cachedViews.includes(view.name)) return;
const { matched, meta, name } = view;
if (!meta.noCache) {
if (matched.length > 2) {
//路由层级大于2时,将父级也加入cachedViews
for (let i = 1; i < matched.length; i++) {
if (!state.cachedViews.includes(matched[i].name)) {
state.cachedViews.push(matched[i].name);
}
}
} else {
state.cachedViews.push(name);
}
}
}
2.要缓存三级菜单的父级vue自己包一层<keep-alive></keep-alive>
,确保include
数组包含三级菜单name
<template>
<div class="page-padding">
<keep-alive :include="cachedViews">
<router-view :key="key"></router-view>
</keep-alive>
</div>
</template>
<script>
export default {
name: "记得要填写name",
computed: {
cachedViews() {
return this.$store.state.tagsView.cachedViews;
},
key() {
return this.$route.path;
},
},
};
</script>
大佬,我照着你这样改但还是不起作用,而且多个路由公用一个组件页面name怎么弄?
大佬,我照着你这样改但还是不起作用,而且多个路由公用一个组件页面name怎么弄?
我也不知道你是什么情况,检查一下菜单缓存要开启,各个name也要对应上才能缓存成功; 缓存也是填页面的name,跟组件没关系啊;
大佬,我照着你这样改但还是不起作用,而且多个路由公用一个组件页面name怎么弄?
我也不知道你是什么情况,检查一下菜单缓存要开启,各个name也要对应上才能缓存成功; 缓存也是填页面的name,跟组件没关系啊;
你的意思是多个路由对应同一页面?那也还是那样填啊,不过我没有试过效果如何; 【2】 的name填的是二级的name,不是三级name
多级路由嵌套缓存的唯一解决方案 #3436
多级路由嵌套缓存的唯一解决方案 #3436
太麻烦了,还要处理路由和面包屑; 缓存二级会导致缓存所有该二级下的所有三级,但我的处理方式是二级vue文件自己套一层keep-alive,传入include和key就可以将三级菜单缓存区分开,这种方法并不需要改路由文件也不需要改面包屑;
多级路由嵌套缓存的唯一解决方案 #3436
太麻烦了,还要处理路由和面包屑; 缓存二级会导致缓存所有该二级下的所有三级,但我的处理方式是二级vue文件自己套一层keep-alive,传入include和key就可以将三级菜单缓存区分开,这种方法并不需要改路由文件也不需要改面包屑;
这种方式的确比他们那种还要处理的简单
用同样的方法处理4级路由嵌套,没有效果
有2点缺陷,1.在3级嵌套的情况下,2级路由的缓存始终无法删除,缺少对应的删除逻辑,也可能与我2级路由设置了重定向有关;2. 在keep-alive存在动态key属性的情况下,会导致多余的缓存页面出现,这些都可以在vue-tool中观察到; 1的解决方法是加个计数器,同时添加对应的删除逻辑,在计数器为0时删除2级缓存,2的解决方法就是去除key属性
还有个bug,三级嵌套路由缓存情况下,2级路由的切换会出现三级页面错乱的情况,而且没找到啥好的解决办法,最后还是改成了 拉平嵌套路由那种方法
@YOOYY 你说得没错
- 雀食少了删除二级缓存的逻辑,三级全关的情况下二级缓存没移除
- 二级目录的vue文件里router带key
<router-view :key="key"/>
雀食也会导致额外的页面生成,因为之前我一直做的页面created里面都只有缓存的请求,并没有发现这个问题
还有个bug,三级嵌套路由缓存情况下,2级路由的切换会出现三级页面错乱的情况,而且没找到啥好的解决办法,最后还是改成了 拉平嵌套路由那种方法
移除key的话会导致页面没有重新加载,依次打开页面1-1、1-2、2-1,从1-2切换到2-1后再切回1-1,此时只是把2二级路由切回1,但下面的三级路由没有更新,保持了之前的状态(1-2),所以造成了这个错乱的情况,解决方法就是在切换二级路由时调用$forceUpdate
刷新,就可以切回正确匹配的页面了
该issue写在一年前,没想到刚好就跟去年写的时候差一天,正牌作者不出手只能自己提点拙见尝试解决。 之前的解决方法有问题:
- 会导致多余的页面生成
- 三级页面全部关掉后二级也始终缓存着一个二级页面
尝试再更新一版解决方法:
1.在tagsView.js
添加缓存逻辑中,将上级菜单加入缓存
ADD_CACHED_VIEW: (state, view) => {
if (state.cachedViews.includes(view.name)) return;
const { matched, meta, name } = view;
if (!meta.noCache) {
if (matched.length > 2) {
//路由层级大于2时,将父级也加入cachedViews
for (let i = 1; i < matched.length; i++) {
if (!state.cachedViews.includes(matched[i].name)) {
state.cachedViews.push(matched[i].name);
}
}
} else {
state.cachedViews.push(name);
}
}
}
2.在tagsView.js
删除逻辑中,判断二级下没有缓存的三级时,将二级缓存也移除
DEL_CACHED_VIEW: (state, view) => {
const index = state.cachedViews.indexOf(view.name);
index > -1 && state.cachedViews.splice(index, 1);
if (view.matched.length > 2) {
//路由层级大于2,检查并移除没有子页面缓存的上级路由
view.matched.every(() => {
const originLength = state.cachedViews.length;
const inuseCacheNames = state.visitedViews.reduce(
(inuseCacheNames, { matched }) => inuseCacheNames.concat(matched.map(({ name }) => name)),
[]
);
state.cachedViews = state.cachedViews.filter((E) => inuseCacheNames.includes(E));
return originLength === state.cachedViews.length;
});
}
}
3.AppMain.vue
中,移除<router-view>
的key
<template>
<section class="app-main">
<transition name="fade-transform" mode="out-in">
<keep-alive :include="cachedViews">
<router-view />
</keep-alive>
</transition>
</section>
</template>
4.二级vue页面做一些改变:
-
AppMain.vue
移除了key后,切换三级页面会丢失动画,要自己套一层<transition>
- 为了解决切到其它二级路由所属页面后切回来三级路由错乱的问题,要在keep-alive激活后调用
$forceUpdate
- 如果页面不符时,调用
$forceUpdate
刷新会多一段额外的过渡动画,所以要自行控制过渡动画(示例中使用了isTransition
变量,可自行调整逻辑)
<template>
<transition :name="isTransition ? 'fade-transform' : ''" mode="out-in" @before-leave="1">
<keep-alive :include="cachedViews">
<router-view />
</keep-alive>
</transition>
</template>
<script>
export default {
name: "记得填写name",
data() {
return { isTransition: true };
},
computed: {
cachedViews() {
return this.$store.state.tagsView.cachedViews;
},
},
activated() {
this.$forceUpdate();
this.$nextTick(() => (this.isTransition = true));
},
deactivated() {
this.isTransition = false;
},
};
</script>
该issue写在一年前,没想到刚好就跟去年写的时候差一天,正牌作者不出手只能自己提点拙见尝试解决。 之前的解决方法有问题:
- 会导致多余的页面生成
- 三级页面全部关掉后二级也始终缓存着一个二级页面
尝试再更新一版解决方法: 1.在
tagsView.js
添加缓存逻辑中,将上级菜单加入缓存ADD_CACHED_VIEW: (state, view) => { if (state.cachedViews.includes(view.name)) return; const { matched, meta, name } = view; if (!meta.noCache) { if (matched.length > 2) { //路由层级大于2时,将父级也加入cachedViews for (let i = 1; i < matched.length; i++) { if (!state.cachedViews.includes(matched[i].name)) { state.cachedViews.push(matched[i].name); } } } else { state.cachedViews.push(name); } } }
2.在
tagsView.js
删除逻辑中,判断二级下没有缓存的三级时,将二级缓存也移除DEL_CACHED_VIEW: (state, view) => { const index = state.cachedViews.indexOf(view.name); index > -1 && state.cachedViews.splice(index, 1); if (view.matched.length > 2) { //路由层级大于2,检查并移除没有子页面缓存的上级路由 view.matched.every(() => { const originLength = state.cachedViews.length; const inuseCacheNames = state.visitedViews.reduce( (inuseCacheNames, { matched }) => inuseCacheNames.concat(matched.map(({ name }) => name)), [] ); state.cachedViews = state.cachedViews.filter((E) => inuseCacheNames.includes(E)); return originLength === state.cachedViews.length; }); } }
3.
AppMain.vue
中,移除<router-view>
的key<template> <section class="app-main"> <transition name="fade-transform" mode="out-in"> <keep-alive :include="cachedViews"> <router-view /> </keep-alive> </transition> </section> </template>
4.二级vue页面做一些改变:
AppMain.vue
移除了key后,切换三级页面会丢失动画,要自己套一层<transition>
- 为了解决切到其它二级路由所属页面后切回来三级路由错乱的问题,要在keep-alive激活后调用
$forceUpdate
- 如果页面不符时,调用
$forceUpdate
刷新会多一段额外的过渡动画,所以要自行控制过渡动画(示例中使用了isTransition
变量,可自行调整逻辑)<template> <transition :name="isTransition ? 'fade-transform' : ''" mode="out-in" @before-leave="1"> <keep-alive :include="cachedViews"> <router-view /> </keep-alive> </transition> </template> <script> export default { name: "记得填写name", data() { return { isTransition: true }; }, computed: { cachedViews() { return this.$store.state.tagsView.cachedViews; }, }, activated() { this.$forceUpdate(); this.$nextTick(() => (this.isTransition = true)); }, deactivated() { this.isTransition = false; }, }; </script>
问题1: 二级vue页面是用的公共页面,只有一个name, 那岂不是每个二级路由都要新建一个路由页面 问题2: 怎么解决路由层级不确定的情况, 比如4层5层
该issue写在一年前,没想到刚好就跟去年写的时候差一天,正牌作者不出手只能自己提点拙见尝试解决。 之前的解决方法有问题:
- 会导致多余的页面生成
- 三级页面全部关掉后二级也始终缓存着一个二级页面
尝试再更新一版解决方法: 1.在
tagsView.js
添加缓存逻辑中,将上级菜单加入缓存ADD_CACHED_VIEW: (state, view) => { if (state.cachedViews.includes(view.name)) return; const { matched, meta, name } = view; if (!meta.noCache) { if (matched.length > 2) { //路由层级大于2时,将父级也加入cachedViews for (let i = 1; i < matched.length; i++) { if (!state.cachedViews.includes(matched[i].name)) { state.cachedViews.push(matched[i].name); } } } else { state.cachedViews.push(name); } } }
2.在
tagsView.js
删除逻辑中,判断二级下没有缓存的三级时,将二级缓存也移除DEL_CACHED_VIEW: (state, view) => { const index = state.cachedViews.indexOf(view.name); index > -1 && state.cachedViews.splice(index, 1); if (view.matched.length > 2) { //路由层级大于2,检查并移除没有子页面缓存的上级路由 view.matched.every(() => { const originLength = state.cachedViews.length; const inuseCacheNames = state.visitedViews.reduce( (inuseCacheNames, { matched }) => inuseCacheNames.concat(matched.map(({ name }) => name)), [] ); state.cachedViews = state.cachedViews.filter((E) => inuseCacheNames.includes(E)); return originLength === state.cachedViews.length; }); } }
3.
AppMain.vue
中,移除<router-view>
的key<template> <section class="app-main"> <transition name="fade-transform" mode="out-in"> <keep-alive :include="cachedViews"> <router-view /> </keep-alive> </transition> </section> </template>
4.二级vue页面做一些改变:
AppMain.vue
移除了key后,切换三级页面会丢失动画,要自己套一层<transition>
- 为了解决切到其它二级路由所属页面后切回来三级路由错乱的问题,要在keep-alive激活后调用
$forceUpdate
- 如果页面不符时,调用
$forceUpdate
刷新会多一段额外的过渡动画,所以要自行控制过渡动画(示例中使用了isTransition
变量,可自行调整逻辑)<template> <transition :name="isTransition ? 'fade-transform' : ''" mode="out-in" @before-leave="1"> <keep-alive :include="cachedViews"> <router-view /> </keep-alive> </transition> </template> <script> export default { name: "记得填写name", data() { return { isTransition: true }; }, computed: { cachedViews() { return this.$store.state.tagsView.cachedViews; }, }, activated() { this.$forceUpdate(); this.$nextTick(() => (this.isTransition = true)); }, deactivated() { this.isTransition = false; }, }; </script>
问题1: 二级vue页面是用的公共页面,只有一个name, 那岂不是每个二级路由都要新建一个路由页面 问题2: 怎么解决路由层级不确定的情况, 比如4层5层
- 按照你引用内容的方式,多个三级路由是共用一个二级路由的,之前的方法才会每个三级都配一个二级(因为使用了key),可以在vuetool中观察到
- 四、五层不在考虑范围内(毕竟标题写的只是三级路由),我的业务也只做到三级,没有多余的时间去测试更多层级是否合适
接上楼,第一个问题看错了,想共用一个二级路由也不是不可以,所有三级共用一个二级name,菜单里二级路由也也都填同一个地址
可以参考这个 https://github.com/PanJiaChen/vue-element-admin/issues/2391#issuecomment-633338531