欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Vue 使用 <keep-alive include> 实现嵌套 <router-view> 缓存,无限层次缓存

程序员文章站 2022-05-29 15:23:33
...

使用 <keep-alive> 实现缓存目前主流的有两种方法

方法一:

  1. 在路由元信息中添加缓存标识:
{
  path: 'json',
  name: 'json',
  meta: {
    ...
    keepAlive: true
    ...
  },
  component: () => import('../views/components/json')
},
  1. 使用 v-if 判断是否缓存
<keep-alive>
   <router-view v-if="$route.meta.keepAlive"/>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"/>

这种方法是比较早版本时使用的方法,当时<keep-alive>还没有include属性。这个方法虽然方便,但是会带来很多bug,比如无法使用<transition>,缓存了不必要的,用来实现嵌套路由操作的<router-view>组件等。

然鹅,我有强迫症,不能接受没有动效 ( ̄(∞) ̄)

因此这里重点讲方法二:

1.使用vuex将路由元信息中keepAlive: true的路由记录下来,将路由的name属性为维护在一个keepAliveList: []里。

2.使用<keep-alive>include属性,来实现动态的组件缓存。

先说一下include属性,它的值可以是:字符串,正则表达式,数组

首先我们需要知道keep-alive可以根据include中的值来匹配当前路由的name属性,来判断这个路由中的组件是否需要缓存。因此我们只需要将keepAliveList: []里保存的需要缓存的路由name传入include即可

因此使用起来就像这样

<keep-alive :include="keepAliveList">
  <router-view :key="key"/>
</keep-alive>

<script>
export default {
  name: 'index',
  data () {
    return {
      keepAliveList: this.$store.getters.getKeepAliveList,
    }
  },
  computed: {
    // 获取缓存列表
    getKeepAliveList () {
      return this.$store.getters.getKeepAliveList
    },
    key () {
      return this.$route.path
    }
  },
  watch: {
    getKeepAliveList (n, o) {
      this.keepAliveList = n
    }
  }
}
</script>

但是

如果遇到嵌套的<router-view>或者嵌套路由(这是很常见的操作),这个时候后面几层<router-view>中的组件缓存会出问题

比如我有下面的三层结构:

 {
    path: '/menu-1',
    name: 'menu-1',
    // 布局文件 ,用来实现多层嵌套的 组件访问,对于多层次的路由访问来说,这是必须的
    component: layout,    
    children: [
      {
        path: 'menu-2',
        name: 'menu-2',
        component: layout,
        children: [
        {
          path: 'menu-3',
          name: 'menu-3',
          meta: {
            keepAlive: true
        },
        component: () => import('../views/components/menu-3.vue')
        }
      ]
    }
  ]
}

文件内容 layout.vue

<template>
   <router-view/>
</template>

<script>
export default {
  name: 'layout'
}
</script>

我想要访问menu-3,在路由之中可视化可以这么看 ( layout 写错了,淦 ):
Vue 使用 <keep-alive include> 实现嵌套 <router-view> 缓存,无限层次缓存
我们可以发现,keep-alive只缓存到第一层,也就是<layout/>这个组件,而这个组件只是一个<router-view/>组件,这明显不是我们想要的。

我们需要把<layout/>这个无用的组件从<keep-alive> <router-view/> <keep-alive/>之中提出,
换句话说是将<menu-3/>提升到<keep-alive>能缓存的那一层,像这样
Vue 使用 <keep-alive include> 实现嵌套 <router-view> 缓存,无限层次缓存

如何解决?

需要把嵌套的<router-view>拍平

也就是在路由守卫中添加一个将无用的 layout 布局过消除的方法:

router.beforeEach((to, from, next) => {
  ...
  handleKeepAlive(to)
  ...
}

/**
 * 递归处理多余的 layout : <router-view>,
 * 让当前组件保持在第一层 index : <router-view> 之下
 * @param to
 */
function handleKeepAlive (to) {
  if (to.matched && to.matched.length > 2) {
    for (let i = 0; i < to.matched.length; i++) {
      const element = to.matched[i]
      if (element.components.default.name === 'layout') {
        to.matched.splice(i, 1)
        handleKeepAlive(to)
      }
    }
  }
}

没有进行 layout 移除时

Vue 使用 <keep-alive include> 实现嵌套 <router-view> 缓存,无限层次缓存

layout 移除之后

Vue 使用 <keep-alive include> 实现嵌套 <router-view> 缓存,无限层次缓存
接下来就可以愉快的缓存多层次的组件了

相关标签: Vue