使用vue的keep-alive 可以缓存加载的组件
keep-alive存在的问题
假设有下面若干tab
[ tab1 tab2 tab3 ]
三个tab通过<keep-alive><router-view/></keep-alive>切换
若:tab1未加载完成时,切换tab2。
则:
- tab1中的异步代码仍会继续执行(如ajax),如果回调中有获取dom元素的代码(包括this.$refs)则会获取不到。
- 由于keep-alive原因,vuex变量变化 ==> tab1(失活)中变量变化 ==> 触发相应方法。
可能会导致控制台报错。
解决办法
基本思路:
若:tab页面未加载完,切换其他tab。
则:不缓存此组件。
若:tab页面已加载完。
则:缓存tab组件。
如何控制组件是否缓存
- 使用keep-alive 标签的include属性或exclude属性。
- 不能使用this.$destroy(),这个可以使该组件不被缓存,但是也切断了与keep-alive的联系,下次打开不能再被缓存。(或者$destroy后再通过改变keep-alive的include属性使其能缓存?未尝试)
- vue-router会缓存同个子路由下,keep-alive的组件。考虑在跳转前,先改变一次路由,清空缓存。再跳转到目标路由。
如何改变keep-alive的prop
- 使用vuex
- Event-Emitter 事件总线bus
如何判断页面是否加载完成
- 判断异步请求全部结束。
- 或requestAnimationFrame,请求帧数达到一定值。(不能保证特别慢的接口)
我的实践
- tab组件created钩子中,通知keep-alive缓存此页。
- tab组件deactivated 钩子中,判断页面是否加载完成。
若未加载完成,则不缓存此页。 - 使用事件总线bus通知keep-alive所在的组件,更改exclude属性。exclude属性为一个存放组件名称的数组。需要缓存时,移除数组中的项。不需要缓存时,数组中添加项。
小结
keep-alive踩坑后,才知道keep-alive组件的代码,deactivated时虽然不可见,但还是会执行的。因此,keep-alive需要慎用,若缓存了太多组件。关联性过多,比如vuex中的值变化,可能导致被keep-alive的看不见的页面代码被执行,大大影响可见页面的交互体验。