keepAlive

缓存展示:
在这里插入图片描述

使用 <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>布局组件等。

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

因此这里重点讲方法二(正在使用的):

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

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

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

首先我们需要知道keep-alive可以根据include中的值来匹配当前路由对应组件的name属性(!!不是路由的name哦,是组件的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 写错了,淦 ):
在这里插入图片描述
我们可以发现,keep-alive只缓存到第一层,也就是<layout/>这个组件,而这个组件只是一个<router-view/>组件,这明显不是我们想要的。

我们需要把<layout/>这个无用的组件从<keep-alive> <router-view/> <keep-alive/>之中提出,
换句话说是将<menu-3/>提升到<keep-alive>能缓存的那一层,像这样
在这里插入图片描述

如何解决?

需要把嵌套的<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>按需加载
 * @param to
 */
async 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)
        await handleKeepAlive(to)
      }
      // 如果没有按需加载完成则等待加载
      if (typeof element.components.default === 'function') {
        await element.components.default()
        await handleKeepAlive(to)
      }
    }
  }
}

   
   

没有进行 layout 移除时

在这里插入图片描述

layout 移除之后

在这里插入图片描述

接下来就可以愉快的缓存多层次的组件了

原文链接:https://blog.csdn.net/qq_41912398/article/details/109576635
Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐