最近开发的几个后台管理系统,都是基于vue-element-admin框架开发的。框架中,默认将所有页面进行了keep-alive缓存。但是在实际需求中,某些页面每次打开都需要刷新数据。这就出现了一个问题:
对于已被缓存的页面,如何进行数据刷新?
目前,在项目开发中,主要用到以下三种方式:
一、监听路由,刷新数据
1 2 3 4 5 6 7 |
watch: { $route: function (newVal) { if (/data-count\/firmCount/.test(newVal.path)) { this.init() } }, }, |
init()方法中,将页面所有缓存的内容、操作的痕迹都进行了重置,让页面回到初始状态。也就是,每次打开目标页面,都如强制刷新一样,没有任何缓存的痕迹。
二、利用生命周期函数,刷新数据
通过keep-alive缓存后的页面,大部分的生命周期函数是不走的。比如:created,mounted等。能够走的生命周期函数就是:activated与deactivated。所以可以在activated生命周期函数中,进行数据刷新。
1 2 3 |
activated() { this.init() }, |
init()方法的写法同上。
三、利用导航守卫清除缓存,刷新数据
1 2 3 4 5 6 7 8 9 10 |
beforeRouteLeave(to, from, next) { //参数(马上去的页面,现在的页面,跳转) if(判断条件){ to.meta.keepAlive = false //将要去的那个页面的缓存清空 }else{ to.meta.keepAlive = true //将要去的那个页面的缓存保留 } next(); }, |
相对来说,前两种方法比较简单粗暴,哪个页面需要就哪个页面使用,缺点就是每个页面需要重置的内容各不相同,处理比较繁琐。
而第三种方法,我们可以封装成一个公共的方法,在需要的页面引用即可。具体可以参考公司大佬的封装,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
//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中根据标记进行刷新与否的处理
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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进行位置处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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 // 新增的代码 } }, |