【Vue.js】<KeepAlive>

60 阅读2分钟

前言

组件的生命周期:

默认情况下,一个组件实例在被替换掉后会被销毁。这会导致它丢失其中所有已变化的状态 —— 当这个组件再一次被显示时,会创建一个只带有初始状态的新实例

Vue 的渲染机制:

具体的渲染步骤如下:

  1. template
  2. AST(directives, props, attrs, events...)
  3. js 逻辑(过滤)
  4. filtered AST
  5. vNode (虚拟节点)
  6. vDOM (虚拟DOM)
  7. 真实 DOM ( rDOM )

Vue 的更新机制:

每一次视图更新:

  1. 每一次更新的 vNode 和上一次的 vNode 进行比较
  2. 对比之后产生差异(diff)
  3. 在有差异的地方打上补丁(patch)
  4. 根据补丁(patch)更新视图

但是,每一次更新比较渲染都要先判断此组件实例是否被缓存(isKeepAlive ?)

什么是 <KeepAlive>

  • <KeepAlive> 是一个内置组件,它的功能是在多个组件间动态切换时缓存被移除的组件实例, 并在内部建立KeepAlive和这些组件之间的映射关系。

<KeepAlive>相关的两个生命周期钩子

  • activated<KeepAlive>包裹的的组件活跃时触发
  • deactivated:<KeepAlive>包裹的的组件失活时触发

注意:

不要乱用keep-alive逻辑 ! ($forceUpdate是一个逃生舱)

KeepAlive上的属性

  • exclude : 按照组件的name属性, 不缓存此name属性(局部注册组件名称)的组件, 其余缓存
  • include : 按照组件的name属性, 缓存此name属性(局部注册组件名称)的组件, 其余不缓存

include & exclude使用注意

  • include & exclude 都是通过name属性(局部注册组件名称)进行查找并缓存组件的
  • 使用类型: 字符串, 数组(v-bind:include="['']"), 正则表达式 (/n|c/)
  • 字符串形式后面不可以有空格
  • 推荐使用数组的形式, 便于维护
  • max: 最多能够缓存的组件实例的个数, 超过组件实例会删除缓存时间最久的组件

    • <KeepAlive> 的行为在指定了 max 后类似一个 LRU 缓存:如果缓存的实例数量即将超过指定的那个最大数量,则最久没有被访问的缓存实例将被销毁,以便为新的实例腾出空间。

异步组件和KeepAlive一起使用可能存在的问题

  • 异步组件一开始不会被 <KeepAlive> 缓存
  • include 不能缓存使用异步组件(只能使用 exclude)
  • 建议异步组件不要和 <KeepAlive> 一起使用

KeepAlive的实现思路

思路, 缓存 vNode ( Vue 源码缓存的是component instance)

判断 vNode 是否为 keepAlive ?

  • 是, 直接去compCache里面的值

  • 否, 创建一个新的节点: 并判断创建出来的节点是否在缓存中 ?

    • 是:写入缓存
    • 不是: 不写入缓存