全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-20 9 分钟 ✍️ juanwangdev

列表过渡

<TransitionGroup> 是 Vue 专为列表设计的过渡组件,支持列表项的进入、离开和位置移动动画。

基础列表过渡

简单实现

vue
<template>
  <TransitionGroup tag="ul" name="fade">
    <li v-for="item in items" :key="item.id" class="list-item">
      {{ item.text }}
      <button @click="remove(item.id)">删除</button>
    </li>
  </TransitionGroup>
</template>

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

const items = ref([
  { id: 1, text: '项目 1' },
  { id: 2, text: '项目 2' },
  { id: 3, text: '项目 3' }
])

const remove = (id) => {
  items.value = items.value.filter(item => item.id !== id)
}
</script>

<style>
.fade-enter-active,
.fade-leave-active {
  transition: all 0.3s ease;
}

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

.fade-leave-active {
  position: absolute;
}
</style>

position: absoluteleave-active 状态时使元素脱离文档流,避免其他元素位置跳动。

排序动画

FLIP 自动动画

vue
<template>
  <TransitionGroup tag="div" name="item" class="grid">
    <div v-for="item in sortedItems" :key="item.id" class="card">
      {{ item.name }} - {{ item.value }}
    </div>
  </TransitionGroup>
  <button @click="sortBy('name')">按名称排序</button>
  <button @click="sortBy('value')">按值排序</button>
</template>

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

const items = ref([
  { id: 1, name: 'C', value: 30 },
  { id: 2, name: 'A', value: 10 },
  { id: 3, name: 'B', value: 20 }
])

const sortKey = ref('id')

const sortedItems = computed(() => {
  return [...items.value].sort((a, b) => a[sortKey.value] - b[sortKey.value])
})

const sortBy = (key) => {
  sortKey.value = key
}
</script>

<style>
.item-move {
  transition: transform 0.4s ease;
}
</style>

Vue 使用 FLIP 技术自动计算新旧位置差异,无需手动编写排序动画逻辑。

添加动画

新项进入效果

vue
<template>
  <TransitionGroup tag="ul" name="slide">
    <li v-for="item in items" :key="item.id">
      {{ item.text }}
    </li>
  </TransitionGroup>
  <button @click="add">添加项目</button>
</template>

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

let nextId = 4
const items = ref([
  { id: 1, text: '项目 1' },
  { id: 2, text: '项目 2' },
  { id: 3, text: '项目 3' }
])

const add = () => {
  items.value.push({ id: nextId++, text: `项目 ${nextId - 1}` })
}
</script>

<style>
.slide-enter-active {
  transition: all 0.3s ease;
}

.slide-enter-from {
  opacity: 0;
  transform: translateY(-20px);
}

.slide-leave-active {
  transition: all 0.3s ease;
}

.slide-leave-to {
  opacity: 0;
  transform: translateY(20px);
}

.slide-move {
  transition: transform 0.3s ease;
}
</style>

性能优化

虚拟化列表

vue
<template>
  <TransitionGroup tag="div" name="item">
    <div v-for="item in visibleItems" :key="item.id" class="item">
      {{ item.content }}
    </div>
  </TransitionGroup>
</template>

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

const allItems = ref([...]) // 大量数据
const scrollTop = ref(0)

const visibleItems = computed(() => {
  // 仅渲染可视区域项
  return allItems.value.filter(item => isInViewport(item))
})
</script>

大数据量列表建议配合虚拟化使用,仅渲染可视区域项,避免 DOM 过多导致性能问题。

动画时长控制

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

列表项较多时,统一设置 :duration 避免动画时长推断错误。

注意事项

  • TransitionGroup 不支持 mode 属性,列表项同时进入/离开
  • 必须为每个列表项设置唯一 key,不能使用索引
  • leave-active 状态设置 position: absolute 避免布局跳动
  • FLIP 动画对 transformopacity 性能最佳,避免修改 width/height

要点总结

  • TransitionGroup 专为列表设计,支持进入、离开、移动三种过渡
  • FLIP 技术自动计算位置差异,简化排序动画实现
  • leave-active 使用 position: absolute 脱离文档流
  • 大数据量列表建议配合虚拟化优化性能

存放路径: articles/VUE/进阶/过度动画与状态复用/列表过渡.md

📝 发现内容有误?点击此处直接编辑

← 上一篇 Vue过渡组件
下一篇 → 状态复用
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库