vue-element-admin项目采用keep-alive全缓存,删除标签移除指定的缓存
程序员文章站
2024-03-26 09:18:47
...
旧方案存在的问题
之前在https://blog.csdn.net/weixin_35958891/article/details/102685382
博客中解决了三级菜单无法缓存的问题,但是那个方案是有bug 的就是缓存只在超过20个后才会删除第一个旧的,也就是会同时存在20个页面缓存的情况,除非f5刷新要不然缓存一直都存在。
解决思路
看了大佬的博客得到启发 https://juejin.im/post/6844903649517240328
,删除标签的时候将缓存删掉。TagsView.vue中删除单个、删除其他、删除全部标签分别触发方法,到AppMain.vue中去实现具体的删除逻辑。下面是vue的keep-alive.js的源码,感兴趣的可以把vue的源码拉下来看一下,
function pruneCacheEntry (cache,key,keys,current) {
const cached = cache[key]
if (cached && (!current || cached.tag !== current.tag)) {
cached.componentInstance.$destroy()
}
cache[key] = null
remove(keys, key)
}
可以看到删除缓存一共分三步
1、调用destory()
2、清空cache
3、移除kes里对应的key值
代码
layout/components/AppMain.vue中
<template>
<section class="app-main">
<transition name="fade-transform" mode="out-in">
<keep-alive :max="20">
<router-view :key="key" />
</keep-alive>
</transition>
</section>
</template>
<script>
import Bus from '../bus.js'
export default {
name: 'AppMain',
computed: {
cachedViews() {
return this.$store.state.tagsView.cachedViews;
},
key() {
return this.$route.fullPath;
}
},
mounted() {
// 关闭标签触发
Bus.$on('removeCache', (name, view) => {
this.removeCache(name, view);
});
},
methods: {
// 获取有keep-alive子节点的Vnode
getVnode() {
// 判断子集非空
if (this.$children.length == 0) return false;
let vnode;
for (let item of this.$children) {
// 如果data中有key则代表找到了keep-alive下面的子集,这个key就是router-view上的key
if (item.$vnode.data.key) {
vnode = item.$vnode;
break;
}
}
return vnode ? vnode : false;
},
// 移除keep-alive缓存
removeCache(name, view = {}) {
let vnode = this.getVnode();
if (!vnode) return false;
let componentInstance = vnode.parent.componentInstance;
// 这个key是用来获取前缀用来后面正则匹配用的
let keyStart = vnode.key.split('/')[0];
let thisKey = `${keyStart}${view.fullPath}`;
let regKey = `${keyStart}${view.path}`;
this[name]({ componentInstance, thisKey, regKey });
},
// 移除其他
closeOthersTags({ componentInstance, thisKey }) {
Object.keys(componentInstance.cache).forEach((key, index) => {
if (key != thisKey) {
// 1 销毁实例(这里存在多个key指向一个缓存的情况可能前面一个已经清除掉了所有要加判断)
if (componentInstance.cache[key]) {
componentInstance.cache[key].componentInstance.$destroy();
}
// 2 删除缓存
delete componentInstance.cache[key];
// 3 移除key中对应的key
componentInstance.keys.splice(index, 1);
}
});
},
// 移除所有缓存
closeAllTags({ componentInstance }) {
// 1 销毁实例
Object.keys(componentInstance.cache).forEach(key => {
if (componentInstance.cache[key]) {
componentInstance.cache[key].componentInstance.$destroy();
}
});
// 2 删除缓存
componentInstance.cache = {};
// 3 移除key中对应的key
componentInstance.keys = [];
},
// 移除单个缓存
closeSelectedTag({ componentInstance, regKey }) {
let reg = new RegExp(`^${regKey}?`);
Object.keys(componentInstance.cache).forEach((key, i) => {
if (reg.test(key)) {
// 1 销毁实例
if (componentInstance.cache[key]) {
componentInstance.cache[key].componentInstance.$destroy();
}
// 2 删除缓存
delete componentInstance.cache[key];
// 3 移除key中对应的key
componentInstance.keys.splice(i, 1);
}
});
}
}
};
</script>
layout/components/TagsView.vue中,这里主要就是用bus触发一下方法,就不贴完整代码了,免得干扰主逻辑,不要忘了引入bus,在beforeDestory生命周期里把bus关一下
closeSelectedTag(view) {
this.$store.dispatch("delView", view).then(({ visitedViews }) => {
if (this.isActive(view)) {
const latestView = visitedViews.slice(-1)[0];
if (latestView) {
this.$router.push(latestView);
} else {
this.$router.push("/");
}
}
//关闭单个
Bus.$emit('removeCache','closeSelectedTag',view)
});
},
closeOthersTags() {
this.$router.push(this.selectedTag);
//关闭其他
Bus.$emit('removeCache','closeOthersTags',this.selectedTag);
this.$store.dispatch("delOthersViews", this.selectedTag).then(() => {
this.moveToCurrentTag();
});
},
closeAllTags(view) {
this.$store.dispatch("delAllViews").then(({ visitedViews }) => {
this.toLastView(visitedViews, view);
//关闭所有
Bus.$emit('removeCache','closeAllTags')
});
},