← 返回题目列表

Vue Transition 和 TransitionGroup 有什么区别?

中等 第 27 / 27 题 更新于 2026/07/29
VueTransition动画列表过渡

简化版

Transition 处理单个元素或组件的进入、离开动画;TransitionGroup 处理列表中多个元素的进入、离开和位置移动动画。前者常用于弹窗和折叠,后者常用于列表增删排序。

详细版

Transition 会在元素进入和离开时添加一组 CSS class。

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

TransitionGroup 面向 v-for 列表,每个子节点必须有稳定 key。

<TransitionGroup name="list" tag="ul">
  <li v-for="item in items" :key="item.id">{{ item.name }}</li>
</TransitionGroup>

面试重点是区分使用对象:单节点用 Transition,列表用 TransitionGroup;列表动画尤其依赖稳定 key,否则 Vue 无法正确判断哪个元素进入、离开或移动。

完整版教学

一、过渡组件解决的是状态变化的视觉连续性

页面状态变化如果直接切换,用户会感觉元素突然出现或消失。 过渡动画的价值不是炫技,而是让用户理解界面发生了什么。 例如弹窗淡入说明“出现一个临时层”,列表项滑出说明“这一项被删除”。

无动画:
状态改变 -> DOM 立即变化

有过渡:
状态改变 -> 进入/离开过程 -> DOM 完成变化

如果一个列表删除 1 项后高度瞬间塌陷,用户可能不知道哪项消失。 给 200ms 的离场动画,认知负担会小很多。

二、Transition 适合单个节点的进入和离开

Transition 包裹一个元素或组件。 当 v-if、动态组件或路由组件切换时,Vue 会在合适时机添加进入和离开的 class。 开发者只需要写 CSS。

<Transition name="fade">
  <div v-if="open" class="modal">弹窗</div>
</Transition>
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.2s ease;
}
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

这里的数字 0.2s 常用于小型浮层。 太短用户感知不到,太长会拖慢操作反馈。

三、TransitionGroup 面向列表,key 是生命线

列表动画和单节点动画最大的不同是:Vue 必须知道每个元素的身份。 TransitionGroup 依赖 key 判断哪个元素新增、哪个删除、哪个移动。 如果用 index 做 key,排序或插入时身份会错乱,动画也会错。

<TransitionGroup name="list" tag="ul">
  <li v-for="todo in todos" :key="todo.id">
    {{ todo.text }}
  </li>
</TransitionGroup>
能力TransitionTransitionGroup
单节点进入/离开适合不主要
列表新增/删除不适合适合
列表移动动画不支持支持
key 要求动态组件常需要必须稳定

假设列表有 10 项,在第 2 项插入新数据。 稳定 id 能让 Vue 知道只有 1 项新增、后面 8 项移动;index key 会让身份映射变混乱。

四、过渡 class 有固定阶段

Vue 的 CSS 过渡 class 分为 from、active、to。 进入时从 enter-fromenter-to,离开时从 leave-fromleave-toactive 控制整个过渡期间的 transition 或 animation。

进入:
enter-from -> enter-active -> enter-to

离开:
leave-from -> leave-active -> leave-to

理解这个流程后,写动画就不是背类名。 from 是起点,to 是终点,active 是怎么从起点走到终点。 比如淡入就是 opacity 从 0 到 1,滑入就是 transform 从偏移到归位。

五、移动动画依赖 FLIP 思路

TransitionGroup 的移动动画常和 FLIP 思路有关。 浏览器先记录元素旧位置,再更新 DOM 得到新位置,最后通过 transform 让元素从旧位置平滑移动到新位置。 这比手动计算每个元素怎么移动要简单。

.list-move {
  transition: transform 0.3s ease;
}
First: 记录旧位置
Last: 计算新位置
Invert: 反向偏移
Play: 播放回新位置

如果一次排序让 20 个元素移动,FLIP 能避免大量手写动画逻辑。 但动画仍有成本,超长列表不应该给每一项都做复杂过渡。

六、动画要兼顾性能和可访问性

前端动画优先使用 opacitytransform,尽量避免频繁触发布局的属性,如 heighttopleft。 复杂列表动画可能造成掉帧。 还要尊重用户的减少动态效果偏好。

@media (prefers-reduced-motion: reduce) {
  .fade-enter-active,
  .fade-leave-active {
    transition: none;
  }
}

记忆钩子:Transition 管一个演员进退场,TransitionGroup 管一队演员换位置。

这句能帮助你快速选择组件。 如果面试官继续追问,就补 key、class 阶段、transform 性能和列表移动。

七、常见误区与追问

  • 误区:TransitionGroup 可以不写 key。 列表过渡必须有稳定 key,否则无法识别元素身份和移动关系。
  • 误区:动画越复杂越能体现能力。 工程动画要服务理解和反馈,过度动画会增加性能和可访问性负担。
  • 误区:所有 CSS 属性都适合动画。 优先使用 opacity 和 transform,谨慎动画化会触发布局的属性。
  • 追问:Transition 的 class 阶段有哪些? 进入和离开都包含 from、active、to 三类阶段。
  • 追问:TransitionGroup 为什么能做移动动画? 它能基于元素位置变化添加 move class,常体现 FLIP 思路。
  • 追问:弹窗适合用哪个? 单个弹窗用 Transition,多个通知列表或排序列表用 TransitionGroup。

八、加强记忆

这题按“单个、列表、性能”记。单节点进出用 Transition,列表增删移动用 TransitionGroup,列表必须稳定 key;CSS 阶段看 from/active/to;动画属性优先 opacity 和 transform,并考虑减少动态效果偏好。