是 Vue 处理列表动画的核心内置组件,专为 v-for 渲染的多个元素设计,使用时需确保结构正确、key 唯一、样式匹配、容器语义合理。

必须写对的结构要点
在 `.vue` 文件的 `` 中,`
常见错误:漏写 `key`、用索引 `index` 当 key、把 `key` 写在 `
- ✅ 正确:
<div v-for="item in list" :key="item.id">{{ item.text }}</div> - ❌ 错误:
<div v-for="(item, i) in list" :key="i">(索引不稳定,增删时 key 会错位) <li>❌ 错误:<code><transitiongroup :key="list.length"></transitiongroup>(key 应在子元素上) -
tag="ul"→ 渲染为无序列表,适合待办项、菜单等 -
tag="div"→ 渲染为块级容器,适合网格、卡片流 -
tag="section"→ 语义更明确,无障碍友好 -
.list-enter-active, .list-leave-active:声明过渡持续时间、缓动函数(如transition: all 0.3s ease) -
.list-enter-from, .list-leave-to:定义起始/结束状态(如opacity: 0; transform: translateY(10px)) -
.list-move(推荐加):解决排序或中间插入时其他项“跳动”问题,加了就能平滑位移(如transition: transform 0.3s ease)
控制容器标签与语义化
` 注意:`tag` 不影响动画逻辑,只改变外层 DOM 结构,不影响内部元素的 enter/leave 动画类名应用位置。 立即学习“前端免费学习笔记(深入)”; 将静态 Vue 页面(index.vue)改造为动态页面(Custom.vue);稿源仅限 index.vue、其引用的 CSS 与资源路径,禁止参考仓库内其他文件。Invoke when user wants to transform a static Vue page into a dynamic data-driven page with Element UI components. 动画类名前缀由 `name` 属性决定(如 `name="list"` → 类名是 `.list-enter-active`)。必须定义至少三组规则: ⚠️ 注意:`.list-enter-to` 和 `.list-leave-from` 一般不用显式写,Vue 会自动补全;重点是 `-from` 和 `-to` 的状态 + `-active` 的过渡行为。 以下是一个可直接复制到 `.vue` 文件中运行的最小可用示例:`、`
` 等语义化容器。用 `tag` 属性指定即可:
写对 CSS 类名才能动起来
完整 SFC 示例(待办列表)
<template>
<div>
<input v-model="newText" @keyup.enter="add" placeholder="输入任务" />
<button @click="add">添加</button>
<TransitionGroup tag="ul" name="list" class="task-list">
<li v-for="task in tasks" :key="task.id" class="task-item">
{{ task.text }}
<button @click="remove(task.id)">×</button>
</li>
</TransitionGroup>
</div>
</template>
<script setup>
import { ref } from 'vue'
const newText = ref('')
const tasks = ref([
{ id: 1, text: '学习 Vue 响应式' },
{ id: 2, text: '掌握 TransitionGroup' }
])
let nextId = 3
const add = () => {
if (!newText.value.trim()) return
tasks.value.push({ id: nextId++, text: newText.value.trim() })
newText.value = ''
}
const remove = (id) => {
tasks.value = tasks.value.filter(t => t.id !== id)
}
</script>
<style scoped>
.task-list {
margin-top: 16px;
padding: 0;
list-style: none;
}
.task-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
background: #f9f9f9;
margin-bottom: 4px;
border-radius: 4px;
}
.list-enter-active,
.list-leave-active,
.list-move {
transition: all 0.25s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(-10px);
}
</style>
不复杂但容易忽略

















