跳到主要内容

Transition 组件原理

<Transition> 看起来像是“给元素加动画”,但它本质上做的是:

在元素进入和离开时,帮你管理一套可控的过渡生命周期。

所以它既不是纯 CSS,也不是单纯的 JavaScript 动画 API,而是 Vue 在“节点插入/移除”时加上的一层协调机制。

面试速答(30 秒版 TL;DR)

  • Transition 只包裹一个根节点或组件。
  • 它会在进入(enter)和离开(leave)阶段,自动添加/移除一组 CSS class,或者触发 JS 钩子。
  • Vue 通过过渡状态把“立即插入/移除 DOM”改造成“先过渡,再完成插入/移除”。
  • 高频搭配:
    • v-if:控制挂载和卸载
    • v-show:控制显示和隐藏

1. 它解决的不是“动画”,而是“时机”

如果没有 Transitionv-if 控制的节点通常是:

  • 条件为真:直接插入
  • 条件为假:直接移除

这意味着节点没有“离场时间”,自然也很难优雅做动画。

Transition 的价值在于:

  • 进入时,先挂上进入态 class,再让浏览器执行过渡
  • 离开时,不是立刻删 DOM,而是等离场过渡结束再删除

2. 最基本的进入/离开流程

<Transition name="fade">
<div v-if="visible">内容</div>
</Transition>

Vue 会自动管理一组 class:

  • fade-enter-from
  • fade-enter-active
  • fade-enter-to
  • fade-leave-from
  • fade-leave-active
  • fade-leave-to

进入阶段

  1. 节点准备插入
  2. 加上 enter-fromenter-active
  3. 下一帧切换到 enter-to
  4. 过渡结束后移除这些 class

离开阶段

  1. 节点准备离开
  2. 加上 leave-fromleave-active
  3. 下一帧切换到 leave-to
  4. 等过渡结束后,真正移除 DOM

3. 为什么 Vue 要分 from / active / to

因为浏览器过渡需要“起点样式”和“终点样式”之间的变化。

例如:

.fade-enter-from,
.fade-leave-to {
opacity: 0;
}

.fade-enter-to,
.fade-leave-from {
opacity: 1;
}

.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}

这样浏览器才能从 opacity: 0 平滑过渡到 opacity: 1,反之亦然。

4. v-ifv-show 配合时有什么区别?

4.1 配合 v-if

  • 控制真实挂载/卸载
  • 更适合“组件确实要进场/退场”

4.2 配合 v-show

  • 本质是不卸载 DOM,只切换 display
  • 更适合频繁切换显隐

面试常用总结:

  • 切换频繁:优先 v-show
  • 首屏不一定渲染:优先 v-if

Transition 只是给这两种切换方式都补上了过渡能力。

5. JavaScript 钩子是怎么参与的?

除了 CSS class,Transition 还支持 JS 钩子:

  • before-enter
  • enter
  • after-enter
  • before-leave
  • leave
  • after-leave

这样你就可以接入:

  • GSAP
  • anime.js
  • 自己写的动画逻辑

如果使用 JS 钩子并显式控制结束时机,Vue 会等待你调用完成回调后再收尾。

6. Transition 的原理可以怎么理解?

从渲染器角度,可以把它看成“在 patch 过程中劫持节点插入和移除”。

简化心智模型:

if (isEnter) {
addEnterClasses(el)
insert(el)
nextFrame(() => switchToEnterTo(el))
whenTransitionEnds(el, cleanupEnterClasses)
}

if (isLeave) {
addLeaveClasses(el)
nextFrame(() => switchToLeaveTo(el))
whenTransitionEnds(el, () => {
remove(el)
cleanupLeaveClasses(el)
})
}

核心点就两句:

  • 进入:插入前后插 class
  • 离开:延迟删除 DOM,等过渡结束再删

7. 为什么有时动画不生效?

7.1 没有设置 transitionanimation

加了类名不代表浏览器就会动,CSS 必须定义过渡属性。

7.2 节点没有稳定 key

尤其切换同级元素时,如果没有合适的 key,Vue 可能复用旧节点,过渡时机就不符合预期。

7.3 嵌套动画结束时机不好判断

复杂嵌套场景中,Vue 自动监听到的结束事件可能不是你真正想等的那个,这时需要手动指定 duration

8. TransitionTransitionGroup 区别

  • Transition:针对单个元素或单个组件切换
  • TransitionGroup:针对列表项的进入、离开、移动

不要把列表过渡全塞给 Transition,这类场景应该用 TransitionGroup

9. 面试高频答法

Q1:Transition 的原理是什么?

:本质是在节点进入和离开时,Vue 渲染器不会直接粗暴地插入或移除 DOM,而是先注入一套过渡 class 或调用 JS 钩子,等待过渡结束后再完成 DOM 的最终状态切换。

Q2:v-ifv-show 配合 Transition 有什么区别?

v-if 是控制节点真实挂载和卸载,适合低频切换;v-show 是保留 DOM、只切换显示状态,适合高频切换。Transition 只是给两者补上过渡时机控制。

速记要点

  • Transition 重点不是动画本身,而是进入/离开的时机控制
  • 通过 *-enter-**-leave-* class 管理状态
  • 离开时会延迟移除 DOM,等过渡结束
  • 列表场景用 TransitionGroup