目录

Keep-alive 用法

李羽秋
李羽秋 2023年03月28日  ·  阅读 1,406

Keep-alive 用法

1. 场景

在平时开发过程中,可能会遇到这样的场景:有一个可以进行筛选的列表页List.vue,点击某一项时进入相应的详情页面,等到你从详情页返回List.vue时,发现列表页居然刷新了!刚刚的筛选条件都没了,这时候keep-alive就登场了,我们先来看看什么是keep-alive。

2. keep-alive是什么?

keep-alive`是`vue`中的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染`DOM

keep-alive 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们

keep-alive可以设置以下props属性:

  • include - 字符串或正则表达式。只有名称匹配的组件会被缓存
  • exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存
  • max - 数字。最多可以缓存多少组件实例,超过max则按照LRU算法进行置换

3. 底层原理

在各个生命周期下所做的事情

  • created:初始化一个cache、keys,cache用来存缓存组件的虚拟dom集合,keys用来存缓存组件的key集合。
  • mounted:实时监听include、exclude这两个的变化,并执行相应操作。
  • destroyed:删除掉所有缓存相关的东西。

对应源码

// src/core/components/keep-alive.js

export default {
  name: 'keep-alive',
  abstract: true, // 判断此组件是否需要在渲染成真实DOM
  props: {
    include: patternTypes,
    exclude: patternTypes,
    max: [String, Number]
  },
  created() {
    this.cache = Object.create(null) // 创建对象来存储  缓存虚拟dom
    this.keys = [] // 创建数组来存储  缓存key
  },
  mounted() {
    // 实时监听include、exclude的变动
    this.$watch('include', val => {
      pruneCache(this, name => matches(val, name))
    })
    this.$watch('exclude', val => {
      pruneCache(this, name => !matches(val, name))
    })
  },
  destroyed() {
    for (const key in this.cache) { // 删除所有的缓存
      pruneCacheEntry(this.cache, key, this.keys)
    }
  },
  render() {
      // 下面讲
  }
}

pruneCacheEntry函数

上面keep-alive源码中,在destroyed销毁生命周期中for循环执行pruneCacheEntry函数,看看该函数内部做了什么?

// src/core/components/keep-alive.js

function pruneCacheEntry (
  cache: VNodeCache,
  key: string,
  keys: Array<string>,
  current?: VNode
) {
  const cached = cache[key]
  if (cached && (!current || cached.tag !== current.tag)) {
    cached.componentInstance.$destroy() // 执行组件的destory钩子函数
  }
  cache[key] = null  // 设为null
  remove(keys, key) // 删除对应的元素
}
  • 1:遍历集合,执行所有缓存组件的$destroy方法
  • 2:将cache对应key的内容设置为null
  • 3:删除keys中对应的元素

render函数

render函数里主要做了这些事:

  • 第一步:获取到keep-alive包裹的第一个组件以及它的组件名称
  • 第二步:判断此组件名称是否能被白名单、黑名单匹配,如果不能被白名单匹配 || 能被黑名单匹配,则直接返回VNode,不往下执行,如果不符合,则往下执行第三步
  • 第三步:根据组件ID、tag生成缓存key,并在缓存集合中查找是否已缓存过此组件。如果已缓存过,直接取出缓存组件,并更新缓存key在keys中的位置(这是LRU算法的关键),如果没缓存过,则继续第四步
  • 第四步:分别在cache、keys中保存此组件以及他的缓存key,并检查数量是否超过max,超过则根据LRU算法进行删除
  • 第五步:将此组件实例的keepAlive属性设置为true,这很重要哦,下面会讲到的!

渲染

咱们先来看看Vue一个组件是怎么渲染的,咱们从render开始说:

  • render:此函数会将组件转成VNode
  • patch:此函数在初次渲染时会直接渲染根据拿到的VNode直接渲染成真实DOM,第二次渲染开始就会拿VNode会跟旧VNode对比,打补丁(diff算法对比发生在此阶段),然后渲染成真实DOM
分类: Vue
标签: