【vue】3.0 keep-alive实现动态缓存以及缓存销毁
概念
keep-alive
keep-alive
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和transition
相似,keep-alive
是一个抽象组件:它自身不会渲染一个DOM
元素,也不会出现在父组件链中。- keep-alive: vue文档
- 组件内的守卫-
beforeRouteLeave
- 导航离开该组件的对应路由时调用
- 可以访问组件实例
this
- 组件内的守卫:
vue-router
文档
前言
后台管理系统中,左侧为功能菜单栏,点击菜单列表,右侧显示该菜单的功能页面,本来是一个非常简单的后台管理系统布局,现在增加了tabs菜单按钮;
点击左侧菜单栏时,右侧页面头部header显示当前的页面标题,形成一个tabs列表,点击可切换页面内容和关闭tab;
现在的需求:
打开之后需要保留的页面在tab不关闭的情况下,保留上一次的状态,而在tab关闭之后,则下次打开会重新请求数据,不会保留上次状态。
初步解决
第一想到的就是利用vue的功能组件
1 | <keep-alive> |
但是这种情况只能实现缓存所有页面,就是不能根据需求实现动态缓存,所有状态都存着呢,愁啊。
解决方案构想:
路由元信息内添加特定字段如:
keepAlive
1 | const router = new VueRouter({ |
父组件内根据路由中的
keepAlive
字段动态使用keep-alive
标签
1 | class Home extends Vue { |
思路
由于现在组件的keep-alive
是动态根据路由元信息中的keepAlive
字段进行动态使用的,所以只要动态改变对应路由元信息的keepAlive
字段就可以实现动态缓存。
实现方案
方案一
利用beforeRouteLeave
改变from
的keepAlive
实现(原思路,网络解决方案之一,有bug)
1 | beforeRouteLeave (to: any, from: any, next: any) { |
bug:首次去C页面,再返回B页面,B并没有缓存,第二次再进入C页面,B页面缓存,且进A页面并不能清除B页面的缓存
方案二(网络方案)
$destroy()
销毁
1 | beforeRouteLeave (to: any, from: any, next: any) { |
bug:销毁之后永远不会被缓存
方案三(网络方案)
- 根据源码看来缓存的组件都会设置一个cache属性,可以通过代码强行移除掉。缺点就是没有彻底销毁依旧占内存
- 具体实现参考
方案四(最优解)
利用keep-alive
的include
属性,利用vuex
动态控制include
达到动态管理缓存
1 | <keep-alive :include="keepAliveList"> |
利用计算属性和vuex获取缓存列表
这里可以使用你自己的规则,原因请继续往下看
1 | <!--vuex--> |
生成缓存列表,列表的值为各组件中name的值集合拼接的字符串
1 | this.$store.commit('setKeepAliveLists',routerComponentNameList.join()) |
点击左侧菜单栏时,更新缓存列表
1 | <!-- 点击左侧菜单的事件函数 --> |
点击右侧tabs关闭标签删除缓存
1 | removeTab(name){ |
下面为主要代码,监听当前路由是否被移除缓存,如果移除缓存则需要销毁该组件,否则内容中的缓存组件会越来越来,影响使用性能;
创建一个mixin.js
文件,然后引入到需要被动态缓存的路由组件中即可;
1 | // 路由缓存管理 |
总结
关于在$store
中保存和删除的过程,各人有各人的方法,我这边只是一种参考,不过多讨论。
不过关于keep-alive
的include
原理,这里简单介绍下,官方(截止到2020年1月)给的方案是正则白名单,也就是说在include
中包含的字段,只要路由的name
满足正则要求,则会缓存,exclude
的规则同样满足,所以这就造成匿名路由的童鞋无法使用keep-alive
。不过也有解决方案,使用beforeRouteLeave
监听,自己做缓存,不过目前我还没试过,后续我试完会新写的。
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我的支持。😘✔