使用vue的keep-alive 可以缓存加载的组件

keep-alive存在的问题

假设有下面若干tab

[ tab1    tab2    tab3 ]

三个tab通过<keep-alive><router-view/></keep-alive>切换

若:tab1未加载完成时,切换tab2。

则:

  1. tab1中的异步代码仍会继续执行(如ajax),如果回调中有获取dom元素的代码(包括this.$refs)则会获取不到。
  2. 由于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

  1. 使用vuex
  2. Event-Emitter 事件总线bus

如何判断页面是否加载完成

  • 判断异步请求全部结束。
  • 或requestAnimationFrame,请求帧数达到一定值。(不能保证特别慢的接口)

我的实践

  1. tab组件created钩子中,通知keep-alive缓存此页。
  2. tab组件deactivated 钩子中,判断页面是否加载完成。
    若未加载完成,则不缓存此页。
  3. 使用事件总线bus通知keep-alive所在的组件,更改exclude属性。exclude属性为一个存放组件名称的数组。需要缓存时,移除数组中的项。不需要缓存时,数组中添加项。

小结

keep-alive踩坑后,才知道keep-alive组件的代码,deactivated时虽然不可见,但还是会执行的。因此,keep-alive需要慎用,若缓存了太多组件。关联性过多,比如vuex中的值变化,可能导致被keep-alive的看不见的页面代码被执行,大大影响可见页面的交互体验。