Vue3中KeepAlive、Teleport、Transition 内置组件是怎么实现的?

Vue3中KeepAlive、Teleport、Transition 内置组件是怎么实现的?
最新回答
许我个未来

2021-07-20 17:24:56

Vue3 中的 KeepAlive、Teleport、Transition 内置组件通过与渲染器的深度协作,分别实现了缓存管理、DOM 层级穿透和过渡动画控制,以下是具体实现原理

1. KeepAlive:基于缓存管理的组件状态保持
  • 解决的问题避免组件频繁创建/销毁带来的性能开销,尤其适用于标签页切换等场景。通过缓存组件实例,保留其状态(如输入框内容、滚动位置等)。

  • 实现原理

    假卸载机制:被 KeepAlive 包裹的组件卸载时,实际被移动到隐藏容器(如 document.createElement('div'))中,而非直接销毁;重新挂载时从隐藏容器恢复。

    缓存管理

    使用 Map 对象存储缓存,键为组件的 vnode.type(即组件选项对象),值为 vnode 对象。

    通过 include/exclude 属性筛选缓存组件,匹配规则为组件的 name 选项。

    缓存修剪策略:当缓存数量超过 max 阈值时,基于 LRU(最近最少使用) 算法移除最久未访问的缓存实例。

    生命周期钩子

    activated:组件从缓存中激活时触发。

    deactivated:组件被缓存时触发。

  • 代码示例

    // 缓存查找与设置逻辑const cacheVNode = cache.get(rawVNode.type);if (cacheVNode) { rawVNode.component = cacheVNode.component; // 复用实例 rawVNode.keptAlive = true;} else { cache.set(rawVNode.type, rawVNode); // 新缓存 // 缓存数量超过 max 时修剪 if (cache.size > max) { const oldestKey = getOldestKey(cache); cache.delete(oldestKey); }}
2. Teleport:突破 DOM 层级的渲染控制
  • 解决的问题解决组件渲染时受父容器样式(如 z-index、overflow: hidden)限制的问题,例如实现全局模态框、通知弹窗等。

  • 实现原理

    渲染器识别:通过组件选项的 _isTeleport 标识判断是否为 Teleport 组件,若是则调用专用 process 函数。

    挂载与更新逻辑

    挂载阶段:根据 props.to(支持 CSS 选择器或 DOM 元素)确定目标容器,将子节点渲染到目标位置。

    更新阶段:对比新旧虚拟节点,仅更新变化的子节点。

    DOM 操作:直接操作真实 DOM,而非依赖虚拟 DOM 的父子关系。

  • 代码示例

    const Teleport = { _isTeleport: true, process(n1, n2, container, anchor, internals) { const { patch } = internals; if (!n1) { // 挂载 const target = typeof n2.props.to === 'string' ? document.querySelector(n2.props.to) : n2.props.to; n2.children.forEach(child => patch(null, child, target, anchor)); } else { // 更新 patchChildren(n1, n2, container); } }};
3. Transition:基于钩子的过渡动画控制
  • 解决的问题封装原生 CSS 过渡的复杂逻辑,提供更声明式的动画控制方式,支持进入(enter)、离开(leave)等场景。

  • 实现原理

    阶段划分:将过渡过程拆分为多个钩子函数,对应 CSS 过渡的关键时间点:

    beforeEnter:设置初始状态(如 opacity: 0)。

    enter:触发动画(如下一帧添加 opacity: 1)。

    afterEnter:动画完成后清理状态。

    类似地定义 leave 相关钩子。

    与渲染器协作

    在组件挂载/卸载前插入钩子调用,通过 requestAnimationFrame 确保动画时机准确。

    支持 CSS 和 JavaScript 两种动画模式,CSS 模式下钩子可省略 done 回调。

  • 代码示例

    // 钩子函数调用顺序示例function onBeforeEnter(el) { el.style.opacity = '0';}function onEnter(el, done) { requestAnimationFrame(() => { el.style.opacity = '1'; el.addEventListener('transitionend', done); });}function onAfterEnter(el) { el.style.opacity = ''; // 清理样式}
共同特点
  • 与渲染器深度集成:均依赖 Vue 的渲染器实现底层逻辑(如 DOM 操作、虚拟节点对比)。
  • 声明式 API:通过组件属性(如 KeepAlive 的 include)或钩子函数(如 Transition 的 beforeEnter)控制行为。
  • 性能优化:KeepAlive 减少重复渲染开销,Teleport 避免不必要的重排,Transition 优化动画性能。

通过以上机制,Vue3 的内置组件在保持灵活性的同时,提供了高效的运行时性能。