为什么需要缓存

总的来说是为了提高用户体验。如下图所示,当选中“家具厨具”后,进入其它页面返回后我们希望选中的还是“家具厨具”,并且停留在原来浏览的位置。
WechatIMG256.jpeg
Vue应用在切换路由后原页面的组件会被销毁,后退时会重新渲染组件,原页面运行中产生的数据会全部丢失。为了达到缓存的目的,Vue提供了keep-alive内置组件。

keep-alive

keep-alive会缓存不活动的组件实例,用keep-alive包裹router-view就可以缓存页面。

  1. <keep-alive >
  2. <router-view :key="$route.fullPath" />
  3. </keep-alive>

这样做会简单粗暴地把所有页面都缓存起来,我们想要的是进入新页面时重新渲染新页面组件,返回上一页面时使用缓存。所以在切换路由时,需要判断是进入新页面还是返回上一个页面,在路由元信息中定义页面之间的层级关系:

  1. {
  2. path: 'staff-performance',
  3. component: () => import('@/views/dashboard/merchant/home/department/staff-performance/index'),
  4. props: true,
  5. meta: { title: '员工业绩', level: 4 }
  6. }

通过比较level的大小就可以判断是进入新页面还是返回上一个页面,如level: 1 => level: 2是进入新页面,level: 3 => level: 2是返回上一个页面。

删除缓存

返回上一个页面时需要销毁新页面,而Vue没有提供手动删除keep-alive缓存的方法。参考动态移除缓存我们可以新建一个page-cache.js文件,定义mixin:

  1. export default {
  2. beforeRouteLeave(to, from, next) {
  3. // 判断是否返回上一页面, 返回上一页面要清除缓存(level: 页面层级,在router.js中配置) 参考https://segmentfault.com/a/1190000015845117
  4. if (from && from.meta.level && to.meta.level && from.meta.level > to.meta.level) {
  5. if (this.$vnode && this.$vnode.data.keepAlive) {
  6. if (this.$vnode.parent && this.$vnode.parent.componentInstance && this.$vnode.parent.componentInstance.cache) {
  7. if (this.$vnode.componentOptions) {
  8. const key = this.$vnode.key == null
  9. ? this.$vnode.componentOptions.Ctor.cid + (this.$vnode.componentOptions.tag ? `::${this.$vnode.componentOptions.tag}` : '')
  10. : this.$vnode.key
  11. const cache = this.$vnode.parent.componentInstance.cache
  12. const keys = this.$vnode.parent.componentInstance.keys
  13. if (cache[key]) {
  14. if (keys.length) {
  15. const index = keys.indexOf(key)
  16. if (index > -1) {
  17. keys.splice(index, 1)
  18. }
  19. }
  20. delete cache[key]
  21. }
  22. }
  23. }
  24. }
  25. this.$destroy()
  26. }
  27. next()
  28. }
  29. }

在需要缓存的页面导入该mixin

只缓存部分页面

缓存部分页面需要修改一下router-view和keep-alive的写法

  1. <keep-alive >
  2. <router-view v-if="$route.meta.keepAlive" :key="$route.fullPath" />
  3. </keep-alive>
  4. <router-view v-if="!$route.meta.keepAlive" :key="$route.fullPath" />

是否开启缓存在路由元信息中配置

  1. {
  2. path: 'staff-performance',
  3. component: () => import('@/views/dashboard/merchant/home/department/staff-performance/index'),
  4. props: true,
  5. meta: { title: '员工业绩', keepAlive: true, level: 4 }
  6. }

注意

嵌套路由需要将keep-alive包裹在最内层的router-view外面,否则页面无法缓存。

优化

所有需要缓存的页面都需要定义一次mixin,比较繁琐。定义为全局mixin,在返回上一个页面时,部分组件不销毁,待优化。

总结

第一步:在路由元信息中定义页面层级以及是否需要缓存
第二步:在需要缓存的组件引入page-cache.js作为mixin