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

1,695 阅读1分钟

image.png

由于admin项目里面有2个菜单使用了 meta: {title: "绩效汇总", icon: "nested", keepAlive: true}, 在测试的时候,打开2个keepAlive都开启的菜单,在点击上面的标签页关闭,在重新打开,会将本来没有在B缓存页面的内容突然存在了A缓存页面的内容,后经过排查是因为2个缓存共用的原因导致,如果没有关闭上面的标签页就没有该BUG产生。

开始了第一次尝试。

当点关闭标签的时候如果不想当前页面缓存 加上

image.png

接着遇到了第一次缓存第二次改为false后打开不缓存了 在关闭标签页面 加上这个

  watch: {
    $route() {
      if (this.$route.meta.keepAlive==false) {
        this.$route.meta.keepAlive=true
      }
    },

尝试后没过效果,还是有缓存。

第2个方案

下面是vue的keep-alive.js的源码

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

把keep-alive里面的 cachedViews方法去掉。引入bus。

<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>

引入bus,用bus触发一下方法,修改layout/components/TagsView.vue

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')
      });
    },
    beforeDestory(){
     Bus.$off('removeCache')
    }