首页 / Vue3 入门教程 / 内置组件(下)—— TransitionGroup、KeepAlive、Teleport

Vue3 入门教程

内置组件(下)—— TransitionGroup、KeepAlive、Teleport

本教程共 40 篇 · 第 33 篇 · 更新于 2026-07-29 · 约 7 分钟阅读

VueVue3 入门教程TransitionGroupKeepAliveTeleport内置组件

33. 内置组件(下)—— TransitionGroup、KeepAlive、Teleport

本节目标:学会三个内置组件——列表动画、组件缓存和 DOM 传送门。

TransitionGroup——列表动画

<TransitionGroup><Transition> 的列表版本,专门给 v-for 渲染的列表添加进入、离开和移动动画。

<Transition> 的区别:

对比TransitionTransitionGroup
包装元素不渲染额外元素默认不渲染,可用 tag 指定
过渡模式支持 mode不支持
key可选必须
类名作用域根元素列表中的每个元素

基本用法:

<TransitionGroup name="list" tag="ul">
  <li v-for="item in items" :key="item">
    {{ item }}
  </li>
</TransitionGroup>
.list-enter-active,
.list-leave-active {
  transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
  opacity: 0;
  transform: translateX(30px);
}

移动动画

上面的例子有个问题:插入或删除元素时,周围元素会”跳”过去,而不是平滑移动。

加上 .list-move 类名解决:

.list-move, /* 移动中的元素 */
.list-enter-active,
.list-leave-active {
  transition: all 0.5s ease;
}

.list-enter-from,
.list-leave-to {
  opacity: 0;
  transform: translateX(30px);
}

/* 离开的元素脱离文档流,不影响其他元素定位 */
.list-leave-active {
  position: absolute;
}
Note

position: absolute 很关键。不加的化,离开的元素还占着位置,其他元素没法平滑移动过去。

交错动画

通过 JavaScript Hooks 和 data-* 属性,可以实现列表元素的交错进入效果:

<TransitionGroup
  tag="ul"
  :css="false"
  @before-enter="onBeforeEnter"
  @enter="onEnter"
  @leave="onLeave"
>
  <li
    v-for="(item, index) in items"
    :key="item.msg"
    :data-index="index"
  >
    {{ item.msg }}
  </li>
</TransitionGroup>
function onEnter(el, done) {
  gsap.to(el, {
    opacity: 1,
    height: '1.6em',
    delay: el.dataset.index * 0.15, // 每个元素延迟 0.15s
    onComplete: done
  })
}

KeepAlive——组件缓存

动态切换组件时,默认离开的组件会被销毁,再切回来时状态全丢了。<KeepAlive> 能缓存组件实例,保留状态。

<KeepAlive>
  <component :is="activeComponent" />
</KeepAlive>

选择性缓存

includeexclude 控制哪些组件需要缓存:

<!-- 字符串 -->
<KeepAlive include="a,b">
  <component :is="view" />
</KeepAlive>

<!-- 正则 -->
<KeepAlive :include="/a|b/">
  <component :is="view" />
</KeepAlive>

<!-- 数组 -->
<KeepAlive :include="['a', 'b']">
  <component :is="view" />
</KeepAlive>
Tip

Vue 3.2.34+ 的 <script setup> 会自动根据文件名推断组件名,不需要手动声明 name

最大缓存数

max 限制缓存数量,超出时按 LRU 策略淘汰最久没用的:

<KeepAlive :max="10">
  <component :is="activeComponent" />
</KeepAlive>

缓存组件的生命周期

<KeepAlive> 缓存的组件有两个特殊生命周期:

import { onActivated, onDeactivated } from 'vue'

onActivated(() => {
  // 首次挂载 + 每次从缓存恢复时调用
})

onDeactivated(() => {
  // 从 DOM 移入缓存时调用
})
Note

onActivated 在首次挂载时也会调用,onDeactivated 在组件真正卸载时也会调用。

Teleport——传送门

<Teleport> 可以把模板的一部分”传送”到 DOM 树的其他位置。最典型的场景是模态框。

为什么需要 Teleport

模态框的代码逻辑上属于某个组件,但视觉上要覆盖全屏。如果模态框嵌在 DOM 树深处,position: fixed 可能因为祖先元素的 transform 属性失效,z-index 也可能被其他元素覆盖。

基本用法

<button @click="open = true">打开模态框</button>

<Teleport to="body">
  <div v-if="open" class="modal">
    <p>模态框内容</p>
    <button @click="open = false">关闭</button>
  </div>
</Teleport>

to 属性接受 CSS 选择器或 DOM 节点。上面这个例子把模态框传送到 <body> 下,脱离了原来的嵌套层级。

Tip

<Teleport> 只改变 DOM 结构,不改变组件的逻辑层级。Props 传递、事件触发、inject 都正常工作。

禁用传送

disabled 属性可以临时关闭传送:

<Teleport :disabled="isMobile">
  <div class="modal">...</div>
</Teleport>

移动端可能希望模态框就地渲染,桌面端才传送到 body。

多个 Teleport 到同一目标

多个 <Teleport> 可以传送到同一个目标,内容按顺序追加:

<Teleport to="#modals">
  <div>A</div>
</Teleport>
<Teleport to="#modals">
  <div>B</div>
</Teleport>

渲染结果:

<div id="modals">
  <div>A</div>
  <div>B</div>
</div>

延迟传送(Vue 3.5+)

defer 属性让 Teleport 等目标元素渲染完成后再挂载:

<Teleport defer to="#late-div">...</Teleport>

<!-- 模板后面才渲染的目标 -->
<div id="late-div"></div>
Note

目标元素必须在同一个渲染周期内出现。如果目标要等异步数据才渲染,Teleport 会报错。

本节回顾

  • <TransitionGroup> 给列表添加进入/离开/移动动画,每个元素必须有 key
  • 移动动画需要 .list-move 类名 + position: absolute
  • <KeepAlive> 缓存组件实例,保留切换前的状态
  • include/exclude 控制缓存范围,max 限制缓存数量
  • 缓存组件用 onActivated/onDeactivated 钩子
  • <Teleport> 把模板传送到 DOM 树的其他位置,适合模态框
  • disabled 可以临时关闭传送,defer 可以延迟挂载