跳到主要内容

内置组件

当然可以!在 Vue 3 中,<Transition><TransitionGroup><KeepAlive><Teleport><Suspense> 是官方提供的内置组件(Built-in Components),用于处理动画、缓存、DOM 挂载位置以及异步依赖等高级场景。下面我将逐一解释它们的作用,并附上可运行的测试案例(使用 Vue 3 + Composition API + Vite 环境风格)。


1. <Transition>:单元素/组件的进入/离开过渡

作用

单个元素或组件添加进入/离开的 CSS 过渡或动画。

常用 props

  • name:过渡类名前缀(默认是 v
  • mode:控制进入/离开的顺序(如 'out-in' 先出后进)

示例

<template>
<div>
<button @click="show = !show">Toggle</button>
<Transition name="fade">
<p v-if="show">Hello Transition!</p>
</Transition>
</div>
</template>

<script setup>
import { ref } from 'vue'
const show = ref(true)
</script>

<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>

✅ 效果:点击按钮时,文字淡入淡出。


2. <TransitionGroup>:列表过渡

作用

多个元素/组件(通常用 v-for 渲染)添加过渡效果,支持移动动画(通过 key 识别元素)。

注意

  • 必须给每个子元素设置唯一的 key
  • 默认渲染为 <span>,可通过 tag prop 修改(Vue 3 中推荐用 as

示例

<template>
<div>
<button @click="add">Add</button>
<button @click="remove">Remove</button>
<TransitionGroup name="list" tag="ul">
<li v-for="item in items" :key="item" class="item">
{{ item }}
</li>
</TransitionGroup>
</div>
</template>

<script setup>
import { ref } from 'vue'

const items = ref([1, 2, 3])

function add() {
items.value.push(items.value.length + 1)
}

function remove() {
items.value.pop()
}
</script>

<style scoped>
.list-enter-active,
.list-leave-active,
.list-move {
transition: all 0.5s ease;
}

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

/* 移动动画 */
.list-move {
transform: translateY(0);
}
</style>

✅ 效果:增删项时有滑入滑出+移动动画。


3. <KeepAlive>:缓存动态组件

作用

包裹动态组件(如 <component :is="..."><router-view>),使其在切换时不被销毁,保留状态(如表单输入、滚动位置)。

常用 props

  • include / exclude:字符串或正则,指定哪些组件缓存
  • max:最多缓存多少组件实例

示例

<!-- App.vue -->
<template>
<div>
<button @click="current = 'A'">Show A</button>
<button @click="current = 'B'">Show B</button>
<KeepAlive>
<component :is="current" />
</KeepAlive>
</div>
</template>

<script setup>
import { ref } from 'vue'
import CompA from './CompA.vue'
import CompB from './CompB.vue'

const current = ref('A')
</script>
<!-- CompA.vue -->
<template>
<div>
<h2>Component A</h2>
<input v-model="msg" placeholder="Type something..." />
<p>You typed: {{ msg }}</p>
</div>
</template>

<script setup>
import { ref } from 'vue'
const msg = ref('')
</script>

✅ 切换回 A 时,输入框内容保留。


4. <Teleport>:传送门(将子节点渲染到 DOM 树任意位置)

作用

将组件内部的 DOM “传送”到页面任意位置(如 body 下),常用于模态框、弹窗、通知等。

prop

  • to:目标选择器(如 'body''#modal-root'

示例

<template>
<div>
<button @click="showModal = true">Open Modal</button>
<Teleport to="body">
<div v-if="showModal" class="modal">
<p>This is a modal!</p>
<button @click="showModal = false">Close</button>
</div>
</Teleport>
</div>
</template>

<script setup>
import { ref } from 'vue'
const showModal = ref(false)
</script>

<style scoped>
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
z-index: 1000;
}
</style>

✅ 模态框实际挂载在 <body> 下,不受父级样式影响。


5. <Suspense>:处理异步依赖(如异步组件、setup 中 await)

作用

在子组件(尤其是异步组件)加载完成前显示 fallback 内容。

注意

  • 只对带有异步 setup() 的组件defineAsyncComponent生效
  • 需配合 await 使用

示例

<!-- App.vue -->
<template>
<Suspense>
<template #default>
<AsyncComp />
</template>
<template #fallback>
<p>Loading...</p>
</template>
</Suspense>
</template>

<script setup>
import { defineAsyncComponent } from 'vue'

const AsyncComp = defineAsyncComponent(() => import('./AsyncComp.vue'))
</script>
<!-- AsyncComp.vue -->
<template>
<div>
<h2>Async Component Loaded!</h2>
<p>Data: {{ data }}</p>
</div>
</template>

<script setup>
// 模拟异步获取数据
const data = await new Promise(resolve => {
setTimeout(() => resolve('Fetched after 2s'), 2000)
})
</script>

✅ 页面先显示 "Loading...",2 秒后显示内容。


总结对比表

组件用途关键点
<Transition>单元素过渡配合 v-if/v-show
<TransitionGroup>列表过渡需要 key,支持 move 动画
<KeepAlive>缓存组件状态用于动态组件,避免重复创建
<Teleport>DOM 传送如 modal、tooltip 挂载到 body
<Suspense>异步加载等待需子组件有 await 或异步 setup