VUE缓存:动态keep-alive
栏目: JavaScript · 发布时间: 5年前
内容简介:路总归是有的,就看愿不愿意剑走偏锋了。在最近的开发中,设计有A、B、C三个页面,试想这样一个场景需求:由于现在组件的keep-alive是动态根据路由元信息中的keepAlive字段进行动态使用的,所以只要动态改变对应路由元信息的keepAlive字段就可以实现动态缓存。
路总归是有的,就看愿不愿意剑走偏锋了。
场景
在最近的开发中,设计有A、B、C三个页面,试想这样一个场景需求:
- 离开B页面进入C页面,缓存B页面数据(keepAlive: true)
- 离开B页面进入A页面,不缓存B页面数据(keepAlive: false)
概念
-
keep-alive
- keep-alive 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 transition 相似,keep-alive 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。
- keep-alive: vue文档
-
组件内的守卫 - beforeRouteLeave
- 导航离开该组件的对应路由时调用
- 可以访问组件实例
this
- 组件内的守卫: vue-router 文档
前置背景:keep-alive 组件实现
- 路由元信息内添加特定字段如:keepAlive
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, children: [ { path: 'bar', component: Bar, // a meta field meta: { keepAlive: true } } ] } ] }) 复制代码
- 父组件内根据路由中的keepAlive字段动态使用keep-alive标签
class Home extends Vue { get keepAlive () { // 获取当前路由的元信息中的keepAlive字段 return this.$route.meta.keepAlive } private render () { return ( <div> { !this.keepAlive && <router-view /> } <keep-alive> { this.keepAlive && <router-view/> } </keep-alive> </div> ) } } export default Home 复制代码
思路
由于现在组件的keep-alive是动态根据路由元信息中的keepAlive字段进行动态使用的,所以只要动态改变对应路由元信息的keepAlive字段就可以实现动态缓存。
实现方案
方案一
- 利用beforeRouteLeave改变from的keepAlive实现(原思路,网络解决方案之一,有bug)
beforeRouteLeave (to: any, from: any, next: any) { // 导航离开该组件的对应路由时调用 // 判断是否是去往页面 C if (to.name !== 'C') { // 不是去 C 页面,不缓存 from.meta.keepAlive = false } else { // 是去 C 页面,缓存 from.meta.keepAlive = true } next() } 复制代码
bug:首次去C页面,再返回B页面,B并没有缓存,第二次再进入C页面,B页面缓存,且进A页面并不能清除B页面的缓存
方案二(网络方案)
- $destroy()销毁
beforeRouteLeave (to: any, from: any, next: any) { // 导航离开该组件的对应路由时调用 // 判断是否是去往页面 C if (to.name !== 'C') { // 不是去 C 页面,不缓存 this.$destroy() } next() } 复制代码
bug:销毁之后永远不会被缓存
方案三(网络方案)
- 根据源码看来缓存的组件都会设置一个cache属性,可以通过代码强行移除掉。缺点就是没有彻底销毁依旧占内存
- 具体实现参考
方案四(最优解)
- 利用keep-alive的include属性,利用vuex动态控制include达到动态管理缓存
- 这边不做赘述,网上有很多相关示例代码,且原理很简单
特殊场景以上方案均不可实现下的解决方案
特殊场景
- 此次项目为移动端项目,并未用到keep-alive的include属性,且如果要加入,则项目很多配置需要修改,比较麻烦
解决方案
- 解决方案与上面的方案一类似
- 区别:
- 不操作beforeRouteLeave中的from对象改变keepAlive
- 直接操作this.$router中对应路由元信息的keepAlive
// 操作指定name的路由的元信息 private changeKeepAlive (parentName: string, name: string, keepAlive: boolean) { // @ts-ignore this.$router.options.routes.map((item: any) => { if (item.name === parentName) { item.children.map((a: any) => { if (a.name === name) { a.meta.keepAlive = keepAlive } }) } }) } beforeRouteLeave (to: any, from: any, next: any) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` if (to.name === 'C') { this.changeKeepAlive('Home', 'B', true) } else { this.changeKeepAlive('Home', 'B', false) } next() } 复制代码
经测试,这种解决方案就不会出现方案一的bug
BY--LucaLJX ( LucaLJX的github )
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- ThinkPHP实现静态缓存和动态缓存
- 青蛙与缓存:简化实用版动态规划
- Vue动态路由缓存不相互影响的解决办法
- RXThinkCMF_TP6 v2.9.3 旗舰版发布,增强底层缓存功能,可动态配置模块缓存
- SpringBoot+Shiro学习之数据库动态权限管理和Redis缓存
- 轻松学会HTTP缓存(强缓存,协商缓存)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。