这个题目有点误导人,但是方向大致是这么个方向,其实不叫清除,而叫动态添加缓存。那么现在说下项目背景,用了vue2.0的后台系统,elementui再加之前没有删干净的乱七八糟的elment-admin的东西。需求嘛就是router外面套了keep-alive,就是从左边的侧边栏点击添加到窗口的很多tab页,切换时候要有缓存,关闭时候应该清掉缓存,现在就是关闭时候也有缓存导致再次打开时候上次的信息还在。看了网上很多强制清缓存的东西,大致意思就是从搞不清楚什么层级的对象里面找cache这个对象再清除掉,然后还有个什么key,我找了一天没找明白,我就换了个思路,特此记录下,给后面也有相同需求的人。
一,找到你写keep-alive的文件。改造成大致这样:
<template>
<section class="app-main">
<transition name="fade-transform" mode="out-in" v-if="$route.meta.keepAlive">
<keep-alive>
<router-view :key="key" />
</keep-alive>
</transition>
<transition name="fade-transform" mode="out-in" v-else>
<router-view :key="key" />
</transition>
</section>
</template>
意思嘛就是说你的路由中的meta的keepAlive是true的用缓存,是false的不用。
二,然后你就需要到你的router的文件里面去吧这个叫keepaAlive的全部false。我们是动态添加嘛,这里相当于一个init
就像这样:
{
path:'/franchisee',
component: Layout,
redirect: 'noredirect',
children:[{
path: 'franchisee-view',
name: 'franchisee-view',
component: () =>import('@/views/franchisee/franchisee-view'),
meta: {
title: '加盟商管理',
icon: 'dashboard',
keepAlive: false
},
},{
path: 'franchisee-detail',
name: 'franchisee-detail',
component: () =>import('@/views/franchisee/franchisee-detail'),
meta: {
title: '加盟商详情',
icon: 'dashboard',
keepAlive: false
},
},{
path: 'franchisee-add',
name: 'franchisee-add',
component: () =>import('@/views/franchisee/franchisee-add'),
meta: {
title: '新增加盟商',
icon: 'dashboard',
keepAlive: false
},
},{
全部写false
三,然后去你TagView.vue文件(没有的话意思就是说你点击你页面的那个tag标签的那个页面上的方法的文件)找到以下两个方法,一个是添加,一个是关闭,没有的话自己写一个。
addViewTags() {
const {
name
} = this.$route;
if (name) {
this.$store.dispatch("addView", this.$route);
this.$store.dispatch("addCachedView", this.$route);
}
this.$route.meta.keepAlive = true
return false;
},
起作用的主要就是这个this.$route.meta.keepAlive=true这个方法,意思就是你点开一个页面tag就动态置为true,只要你不关闭,切换时候它还是true。这样缓存就实现啦。
四,关的时候清除
还是在刚刚的文件上,关闭的时候把刚刚那个属性设置为false就行啦
closeSelectedTag(view) {
if (this.isActive(view)) { view.meta.keepAlive = false }
this.$store.dispatch("delCachedViewThis", this)
console.log(this)
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("/");
}
}
});
},
下面的那些你们都可以不用看 主要是if (this.isActive(view)) { view.meta.keepAlive = false }这句话。哦。调用了方法是吧?我一起贴上来。
isActive(route) {
return route.path === this.$route.path;
},
再附上结构的代码
<div class="tags-view-container">
<scroll-pane ref="scrollPane" class="tags-view-wrapper">
<div class="a-flex-rfsfe">
<router-link v-for="tag in visitedViews" ref="tag" :class="isActive(tag) ? 'active' : ''"
:to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }" :key="tag.path"
class="tags-view-item " style="margin-left: 4px;" @click.middle.native="closeSelectedTag(tag)"
@contextmenu.prevent.native="openMenu(tag, $event)">
<span>{{ tag.title }}</span>
<!-- <span v-show="visitedViews.length > 1" -->
<span class="el-icon-close a-ml-08" style="width: 9px; height: 9px; padding-bottom: 3px"
@click.prevent.stop="closeSelectedTag(tag)" />
</router-link>
</div>
</scroll-pane>
其实这里看具体的代码没有意义。毕竟大家的项目都不同,不可能照抄。掌握到思想的精髓就行了。意思就是初始时候全部置为false没有缓存,然后添加tag的时候动态改为true,关闭时候再改为false。这样就比你强制去清除那个什么cache简单多啦。
就这,希望能帮到大家。
后续。后来,发现这个方法也是不可行的,这样的话,需要缓存和不需要缓存的就无法区分开来了。记录下此问题的解决办法。就是搞个白名单,需要缓存的放入到白名单里面,然后在需要缓存的路由的meta里添加一个新属性,如果是关闭的话就把这个属性添加上,就不需要缓存了,如果没有这个属性又在白名单中的话就需要缓存。新开一个窗口先判断有没有,有并在白名单中,就添加上缓存属性,切换的之前删掉,切换的时候就是又没有了。白名单加动态删除添加属性来双重控制。上代码。
layout/components/TagsView.vue
export default {
components: {
ScrollPane,
},
data() {
return {
visible: false,
top: 0,
left: 0,
selectedTag: {},
whiteList: ['project-add', 'station-add', 'customer-add', 'franchisee-add', 'station-apply', 'station-construction', 'price-edit', 'project-confirmed', 'device-add', 'device-edit', 'device-type-edit', 'bank-card-add', 'staff-add', 'staff-exit', 'franchisee-change']
};
},
computed: {
visitedViews() {
return this.$store.state.tagsView.visitedViews;
},
},
watch: {
$route() {
this.addViewTags();
this.moveToCurrentTag();
},
visible(value) {
if (value) {
document.body.addEventListener("click", this.closeMenu);
} else {
document.body.removeEventListener("click", this.closeMenu);
}
},
},
mounted() {
this.addViewTags();
},
methods: {
// generateTitle, // generateTitle by vue-i18n
isActive(route) {
return route.path === this.$route.path;
},
addViewTags() {
const {
name
} = this.$route;
this.$route.meta.keepAlive = false;
let isKeep = this.whiteList.filter((item, index) => { return item == name });
if (isKeep.length == 1 && !this.$route.meta.hasOwnProperty('hash')) {
this.$route.meta.keepAlive = true;
}
if (name) {
this.$store.dispatch("addView", this.$route);
this.$store.dispatch("addCachedView", this.$route);
}
if (this.$route.meta.hasOwnProperty('hash')) {
delete this.$route.meta.hash;
}
return false;
},
moveToCurrentTag() {
const tags = this.$refs.tag;
this.$nextTick(() => {
for (const tag of tags) {
if (tag.to.path === this.$route.path) {
this.$refs.scrollPane.moveToTarget(tag);
// this.$route.meta.keepAlive = true
// when query is different then update
if (tag.to.fullPath !== this.$route.fullPath) {
this.$store.dispatch("updateVisitedView", this.$route);
}
break;
}
}
});
},
refreshSelectedTag(view) {
console.log("view123", view);
this.$store.dispatch("delCachedViewThis", this).then(() => {
const {
fullPath
} = view;
console.log("fullPath", fullPath);
this.$nextTick(() => {
this.$router.replace({
path: fullPath,
});
});
});
},
closeSelectedTag(view) {
if (this.isActive(view)) {
view.meta.keepAlive = false;
view.meta.hash = "del";
}
this.$store.dispatch("delCachedViewThis", this)
console.log(this)
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("/");
}
}
});
},
closeOthersTags() {
this.$router.push(this.selectedTag);
this.$store.dispatch("delOthersViews", this.selectedTag).then(() => {
this.moveToCurrentTag();
});
},
closeAllTags() {
this.$store.dispatch("delAllViews");
this.$router.push("/");
},
openMenu(tag, e) {
const menuMinWidth = 105;
const offsetLeft = this.$el.getBoundingClientRect().left; // container margin left
const offsetWidth = this.$el.offsetWidth; // container width
const maxLeft = offsetWidth - menuMinWidth; // left boundary
const left = e.clientX - offsetLeft + 15; // 15: margin right
if (left > maxLeft) {
this.left = maxLeft;
} else {
this.left = left;
}
this.top = e.clientY;
this.visible = true;
this.selectedTag = tag;
},
closeMenu() {
this.visible = false;
},
},
};