欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

vue-element-admin项目采用keep-alive全缓存,删除标签移除指定的缓存

程序员文章站 2024-03-26 09:18:47
...

旧方案存在的问题

之前在https://blog.csdn.net/weixin_35958891/article/details/102685382博客中解决了三级菜单无法缓存的问题,但是那个方案是有bug 的就是缓存只在超过20个后才会删除第一个旧的,也就是会同时存在20个页面缓存的情况,除非f5刷新要不然缓存一直都存在。
vue-element-admin项目采用keep-alive全缓存,删除标签移除指定的缓存

解决思路

看了大佬的博客得到启发 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值

vue-element-admin项目采用keep-alive全缓存,删除标签移除指定的缓存

代码

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')
      });
    },
相关标签: el-element-admin