<vue优化> keepAlive路由元信息进行页面缓存

1,186 阅读4分钟

使用< keep-alive >

  • < keep-alive >包裹动态组件时,会缓存不活动的组件实例,而不是销毁该组件(注释:有条件渲染的组件包括使用了v-if、router-view,但不包括v-show)
  • 使用keep-alive的组件,多出了activated和deactivated两个生命周期钩子。

以A <=> B <=> C三个页面构成的页面场景,导航守卫全体上岗,B页面初始化阶段读取localStroage。

在没有包裹情况下

  • 从A页面跳转到B页面,生命周期经历了:
  1. beforeRouteLeave(A页面的导航守卫)
  2. beforeEach
  3. beforeEnter(路由独享守卫)
  4. beforeRouteEnter
  5. beforeResolve
  6. afterEach
  7. beforeCreate - created - beforeMount (B页面实例的初始化)
  8. beforeDestroy - destroyed (A页面实例的销毁)
  9. mounted(B页面实例挂载)
  10. beforeUpdate - updated(B页面请求数据后更新)

至此页面切换的生命周期变化已无差别。


包裹情况下(设置只缓存B)

  • 从A页面跳转到B页面,生命周期经历了
  1. beforeRouteLeave (A页面的导航守卫)
  2. beforeEach
  3. beforeEnter
  4. befroeRouteEnter
  5. beforeResolve
  6. afterEach
  7. beforeCreate - created - beforeMount (B页面实例的初始化)
  8. beforeDestroy - destroyed (A页面实例的销毁)
  9. mounted(B页面实例挂载)
  10. beforeUpdate - activated - updated(B页面请求数据后更新)
  • 从B页面回到A页面,生命周期经历了
  1. beforeRouteLeave(B页面)
  2. beforeEach
  3. beforeEnter
  4. beforeRouteEnter
  5. beforeResolve
  6. afterEach
  7. beforeCreate - created - beforeMount (A页面实例初始化)
  8. deactivated (B页面失活)
  9. mounted (A页面实例绑定)
  • A页面第二次进入B页面:
  1. beforeRouteLeave
  2. beforeEach
  3. beforeEnter
  4. beforeRouteEnter
  5. beforeResolve
  6. afterEach
  7. beforeDesroy - destroyed
  8. activated

在以上场景中,提出需求,当A页跳转B页时,B需要重新获取数据;B跳转到C再返回时,B使用之前的缓存而不重新获取数据

方法一:简单实现,使用传参方式

  1. 在A页面跳转到B页面时,给push再附带一个额外的参数params:{isUseCache:false}

  1. 在B页面beforeRouteEnter或activated钩子中,判断isUseCache,选择性进行数据请求。

(不选择在created、beforeMount、mounted钩子: 无意义操作,因为二次进入B页面并不会触发这些钩子,失去了判断的时机)

方法二:路由元信息标记

  • 使用路由元信息标记,去往B的路由,给标记一个isUseCache参数,并初始化为false,意为不使用缓存

  • 在A去B的路上,这个标记应为false
  • B仍然可以在beforeRouteEnter或activated钩子中判断标记选择性获取数据

(else判断需要重置一次isUseCache,因为C到A)

  • 在C回去B的路上,这个标记应为true
  • 这里选择B去C后改变isUseCache状态,并且这个时刻在C页面的beforeRouteLeave钩子中发生会更加严谨(beforeRouteEnter就改变了状态,万一C选择了A为出口时,就会变得难以理解了,并且,选择这个时机可拓展更多逻辑)

再提出一个场景和需求:现有A、B两个页面,B需要承接一个query参数显示不同内容。当A跳转到最近访问的一个B页面,以读取缓存的方式代替请求数据。最近跳转的三个B页面,皆被认为“最近访问的页面”。

  • 仍然选择用元信息来标记。(路由传参是写死的一个状态,不够灵活)

  • B仍然可以在beforeRouteEnter或activated钩子中判断标记,选择性获取数据

  • 但是选择判断的条件有所改变:最近访问的B页面,这可通过每次进入B页面获取$route对象上的fullPath属性作为该页面的唯一象征,然后存入哪?对,元信息中标记个数组配合往后的shift和push来造个队列容器。

  • 在beforeRouteEnter中作这样的判断,即可

以此类推,业务场景还可以扩展一下到动态路由配置

此时判断状态,选择性重新获取数据的时机稍有改变,在动态路由配置下

  • 首次进入B页面会经历beforeRouteEnter和activated钩子
  • 但在B页面内跳转到B/1、B/2诸如此类的路由时,就不会再走以上两个钩子了,继而会走一个beforeRouteUpdate()
  • 当离开B页面,仍会继续走beforeRouteLeave和deactivated

这里自己也试了一下改好,代码和测试那些放在了这里,github.com/AlanNgaiJX/…


这篇Blog是看了两个前辈自己进行修改实践而记录下来的,在文章中还有页面滚动问题的修复,采用了两个router-view并在路由元信息中记录多一个字段用来条件缓存的做法也更加符合业务场景。小弟还是个新手,正在尝试实践一下更多的优化手段也会更新在上面的小仓库中。

Zrory:www.jianshu.com/p/9cefe3d27…

锤哥:juejin.cn/post/684490…