最近开发的几个后台管理系统,都是基于vue-element-admin框架开发的。框架中,默认将所有页面进行了keep-alive缓存。但是在实际需求中,某些页面每次打开都需要刷新数据。这就出现了一个问题:
对于已被缓存的页面,如何进行数据刷新?
目前,在项目开发中,主要用到以下三种方式:
一、监听路由,刷新数据
watch: {
$route: function (newVal) {
if (/data-count\/firmCount/.test(newVal.path)) {
this.init()
}
},
},
init()方法中,将页面所有缓存的内容、操作的痕迹都进行了重置,让页面回到初始状态。也就是,每次打开目标页面,都如强制刷新一样,没有任何缓存的痕迹。
二、利用生命周期函数,刷新数据
通过keep-alive缓存后的页面,大部分的生命周期函数是不走的。比如:created,mounted等。能够走的生命周期函数就是:activated与deactivated。所以可以在activated生命周期函数中,进行数据刷新。
activated() {
this.init()
},
init()方法的写法同上。
三、利用导航守卫清除缓存,刷新数据
beforeRouteLeave(to, from, next) { //参数(马上去的页面,现在的页面,跳转)
if(判断条件){
to.meta.keepAlive = false //将要去的那个页面的缓存清空
}else{
to.meta.keepAlive = true //将要去的那个页面的缓存保留
}
next();
},
相对来说,前两种方法比较简单粗暴,哪个页面需要就哪个页面使用,缺点就是每个页面需要重置的内容各不相同,处理比较繁琐。
而第三种方法,我们可以封装成一个公共的方法,在需要的页面引用即可。具体可以参考公司大佬的封装,如下:
//RouteMixin.js
export default {
beforeRouteLeave(to, from, next) { // 离开路由之前执行的函数
if (this.hasCached(from) && this.hasCached(to)) {
const vnode = this.$vnode
const key = vnode.key// 当前关闭的组件名
if (key && vnode.parent) {
const cache = vnode.parent.componentInstance.cache// 缓存的组件
const keys = this.$vnode.parent.componentInstance.keys// 缓存的组件名
if (keys) {
keys.splice(0, keys.length)
}
if (cache) {
for (const k in cache) {
delete cache[k]
}
}
}
}
if (this.hasCached(to)) {
to.meta.keepAlive = true
} else {
to.meta.keepAlive = false
}
next()
},
methods: {
hasCached(route) { // 根据需要定制缓存与否的规则
const matched = route.matched
const current = matched[matched.length - 1]
const parent = current.parent
if (parent && (parent.components.default.name === 'Layout' || parent.components.default.name === 'BlankLayout')) {
return true
}
return false
},
},
}
需求是千变万化的,这不,在vue-element-admin项目中,关于页面的缓存刷新,最近又遇到一个新问题:
对于已被缓存的页面,如何进行前进刷新后退不刷新?
也就是说,同一个页面,从上级页面或兄弟页面到达时,刷新,从下级页面返回时,不刷新。这应该怎么处理呢? 最终,进行一番搜索,解决如下:
在beforeRouteLeave中做标记,在activated中根据标记进行刷新与否的处理
beforeRouteLeave(to, from, next) {
if (to.path === '/data-count/focusGroup') {//去下级页面时打标记
this.$route.meta.isBack = true
} else {
this.$route.meta.isBack = false
}
next()
},
activated() {
if (!this.$route.meta.isBack) {
this.init()
}
},
由此,又延申出一个问题:
从下级页面返回时,页面如何定位到历史位置?
处理过前进刷新后退不刷新的问题后,这个问题变得相对简单了,我们只需在上述代码的基础上,进行如下处理:
在beforeRouteLeave中记录scrollTop,在activated中根据记录的scrollTop进行位置处理
beforeRouteLeave(to, from, next) {
if (to.path === '/data-count/focusGroup') {
this.$route.meta.isBack = true
this.scrollTop = this.$refs.proTable.$el.scrollTop || 0 // 新增的代码
} else {
this.$route.meta.isBack = false
}
next()
},
activated() {
if (!this.$route.meta.isBack) {
this.init()
} else {
this.$refs.proTable.$el.scrollTop = this.scrollTop // 新增的代码
}
},