内建组件

2025/3/11 Vue3组件

# KeepAlive

keepAlive 是为了避免频繁的销毁,创建带来的性能消耗。它的本质是缓存管理,加上特殊的挂载/卸载逻辑。

  1. 缓存当前的实例
  2. 构建一个隐藏容器,失活时从移动到隐藏容器中,激活时从隐藏容器中复原
  3. 默认插槽即是被缓存的组件
  4. 组件挂载时,尝试从缓存中读取,读取到了,则说明挂载过了,需要激活;没有读取到,则添加到缓存中
  5. vnode 添加 shouldKeepAlive 标识,在组件卸载的时候,只是让其时活,而并非真的卸载
  6. 为组件添加 keptAlive 标识,如果存在,在挂载的时候,让其激活,不会触发组件的挂载逻辑
  7. props 接收 include , exclude, max 属性,控制组件的缓存

KeepAlive (opens new window)

# Teleport

通常情况下,将虚拟 DOM 渲染为真实 DOM 时,最终渲染的真层 DOM 的层级结构与虚拟 DOM 的层级结构一致。

<div id="box" style="z-index: -1;">
  <Overlay />
</div>

这个例子中,即使 Overlay 的层级再高,他也无法遮挡父级的内容。如果可以把 Overlay 渲染到 body 上,那么 Overlay 就可以覆盖整个页面。

  1. 含有 __isTeleport 标识的组件类型, process 函数处理渲染逻辑
  2. 如果旧的节点 n1 不存在,则全部挂载,否则执行更新
  3. 更新可能是 to 属性变化引起的,需要对比 to 属性,如果变化了,则需要对内容进行移动处理

Teleport/TeleportImpl (opens new window)

# Transition

原理:

  1. 当 DOM 被挂载时,将动效附加到该元素上,
  2. 当 DOM 被卸载时,等附加到该元素上的动效执行完毕后,再卸载该元素。

他本身不会渲染任何额外的内容,只是通过默认插槽读取过渡元素,并渲染。

它的作用就是在过度元素的虚拟节点上添加 transform 相关的钩子函数。

实现:

  1. 基于虚拟 DOM 实现的,整个过程分为 3 个大阶段, before, leave, appear, 每个阶段分为 4 个部分,比如:beforeEnter, enter, afterEnter, enterCancelled
  2. 在挂载阶段,会根据节点来判断是否需要添加动效,则调用 transform.beforeEnter 钩子函数,在卸载阶段,则调用 transform.afterLeave 钩子函数
const transition = {
  neame: 'transition',
  setup(props, { slots }) {
    return () => {
      const innerVnode = slots.default()
      innerVnode.transition = {
        beforeEnter(el) {
          // 设置初始状态
          el.classList.add('enter-from')
          el.classList.add('enter-active')
        },
        enter(el){
          // 下一帧切换到结束
          nextFrame(()=>{
            el.classList.remove('enter-from')
            el.classList.add('enter-to')
            // 监听过渡结束
            el.addEventListener('transitionend', ()=>{
              el.classList.remove('enter-to')
              el.classList.remove('enter-active')
            })
          })
        },
        leave(){
          // 重置初始状态
          el.classList.add('enter-from')
          el.classList.add('enter-active')
          
          // 强制 reflow ,使初始状态生效
          document.body.offsetHeight
          
          nextFrame(()=>{
            el.classList.remove('enter-from')
            el.classList.add('enter-to')
            
            el.addEventListener('transitionend', ()=>{
              el.classList.remove('enter-to')
              el.classList.remove('enter-active')
              // 调用 transform.leave 钩子的函数的第二个参数,完成 dom 的卸载
              performRemove()
            })
          })
        }
      }
    }
  }
}

原生 dom 的过渡效果实现

Transition (opens new window)

Last Updated: 2026/06/09/ 06:29:26