vue3 第十六节(keep-alive 内置组件)使用及注意事项详解

1,443 阅读3分钟

keep-alive

1、目的

在使用组件时,有时我们需要将组件进行缓存,而不是重新渲染,用以提高性能,避免重复加载DOM,提升用户的体验keep-alive 组件可以做到这一点,它允许你缓存组件实例,而不是销毁它们,并在需要的时候重新使用它们。

2、作用

keep-alive 组件允许你缓存组件实例,而不是销毁它们,并在需要的时候重新使用它们。这可以提高性能,避免重复加载DOM,提升用户的体验。 比如:

@params currentView :当前活跃的组件名称
<keep-alive>
  <!-- 动态组件 -->
  <component :is="currentView"></component>
</keep-alive>

3、用法

keep-alive 在vue3中接收三个参数include:一个字符串或正则表达式数组,包含才会缓存该组件用于匹配 需要 缓存的组件名称或组件实例

exclude:一个字符串或正则表达式数组,不包含当前组件才会缓存;即用于匹配 不需要 缓存的组件名称或组件实例max:一个数字,用于限制缓存的组件实例的数量。当达到这个数值时,会自动将最不活跃的组件销毁,以保证最大组件实例数量,即执行类似数组的push操作,进行先进先出的缓存策略 比如在app.vue 文件中

<keep-alive>
  <router-view></router-view>
</keep-alive>

<template>
<!-- 不缓存 Header,Footer 组件-->
  <keep-alive exclude="Header,Footer" :max="3">
    <component :is="currentView"></component>
  </keep-alive>
  <!-- 缓存 Header,Footer 组件-->
  <keep-alive include="Header,Footer">
    <component :is="currentView"></component>
  </keep-alive>
  <!-- 使用正则表达式,缓存 Header,Footer 组件 -->
  <keep-alive include="/Header|Footer/">
    <component :is="currentView"></component>
  </keep-alive>
  <!-- 使用数组,缓存 Header,Footer 组件 -->
  <keep-alive include="[Header, Footer]">
    <component :is="currentView"></component>
  </keep-alive>
</template>

注意由于vue组合式api 中没有显性的进行组件名称命名(name),故使用 <script setup> 的单文件组件会自动根据文件名生成对应的 name 选项,无需再手动声明 而在 选项式api中需要显性命名 如:

<script>
  export default{
    name: 'Header' // 组件名称
  }
</script>

4、执行生命周期

keep-alive 组件的生命周期 1、组件第一次进入,即没有被缓存的时候,会执行 setup()、 onBeforeMount() 、onMounted()、onActivated() (没有keep-alive时候,首次执行:setup()、 onBeforeMount() 、onMounted()) 2、组件被缓存的时候,会执行onActivated() 3、组件被激活的时候,会执行onActivated() 4、组件被移除的时候,会执行onDeactivated() 下图: 请添加图片描述

5、执行原理

……

  function pruneCache(filter?: (name: string) => boolean) {
      cache.forEach((vnode, key) => {
        const name = getComponentName(vnode.type as ConcreteComponent)
        if (name && (!filter || !filter(name))) {
          // 当前缓存的组件名称 和 当前活跃的组件名称不相同,则移除该组件
          pruneCacheEntry(key)
        }
      })
    }

  function pruneCacheEntry(key: CacheKey) {
    const cached = cache.get(key) as VNode
    if (!current || !isSameVNodeType(cached, current)) {
      // 卸载
      unmount(cached)
    } else if (current) {
      // current active instance should no longer be kept-alive.
      // we can't unmount it now but it might be later, so reset its flag now.
      // 重新设置缓存标识
      resetShapeFlag(current)
    }
    cache.delete(key)
    keys.delete(key)
  }

  // prune cache on include/exclude prop change
  // 观测 include | exclude 的值变化,并且能观测到更新后的DOM,进行缓存更新
  watch(
    () => [props.include, props.exclude],
    ([include, exclude]) => {
      include && pruneCache(name => matches(include, name))
      exclude && pruneCache(name => !matches(exclude, name))
    },
    // prune post-render after `current` has been updated
    { flush: 'post', deep: true },
  )

  ……
  // 判断是否达到最大缓存数量
  if (max && keys.size > parseInt(max as string, 10)) {
    pruneCacheEntry(keys.values().next().value)
  }
……

vue3 中,keep-alive 使用 cache 一个 Map 对象,key 是组件名称,value 是组件实例,通过缓存组件实例,避免重复加载DOM,提升用户体验。 而在vue2 中,keep-alive 使用 cache 一个 Object 对象;相比较Map 对象性能更好;

仅代表个人观点,如有错误,欢迎批评指正