外观
Vue Transition 实战
是什么
Vue 内置的 <Transition> 组件:把「元素插入/移除」和「CSS 动画」自动接起来。它解决的问题是:JS 里 v-if 移除元素的瞬间,CSS 动画来不及播——Transition 会等动画播完才真正移除。
这是 Vue 相对 React 的原生优势(React 要装第三方库才有同等体验),做交互体验值得用好它。
最小示例:淡入淡出
vue
<script setup>
import { ref } from 'vue'
const show = ref(true)
</script>
<template>
<button @click="show = !show">切换</button>
<Transition name="fade">
<p v-if="show">我被优雅地淡入淡出</p>
</Transition>
</template>
<style>
/* name="fade" → 自动接上 .fade-enter-* / .fade-leave-* 这组类 */
.fade-enter-active,
.fade-leave-active { transition: opacity 250ms ease, transform 250ms ease; }
.fade-enter-from { opacity: 0; transform: translateY(8px); } /* 进场起点 */
.fade-leave-to { opacity: 0; transform: translateY(-8px); } /* 离场终点 */
</style>类名规律(name="fade" 时):
| 类名 | 时机 |
|---|---|
fade-enter-from | 进场起点(刚插入) |
fade-enter-active | 进场全程(写 transition/animation 在这) |
fade-leave-active | 离场全程 |
fade-leave-to | 离场终点 |
实战一:模态框(遮罩 + 面板双层动画)
vue
<Transition name="modal">
<div v-if="open" class="mask" @click="open = false">
<div class="panel" @click.stop>…</div>
</div>
</Transition>
<style>
.mask { position: fixed; inset: 0; background: rgba(0,0,0,.4); display: grid; place-items: center; }
.mask, .panel { transition: all 300ms cubic-bezier(.22,1,.36,1); }
.panel { background: #fff; border-radius: 12px; padding: 24px; }
.modal-enter-from, .modal-leave-to { opacity: 0; }
.modal-enter-from .panel, .modal-leave-to .panel { transform: translateY(16px) scale(.98); }
/* 面板比遮罩多动一点:错落感 */
.modal-leave-active { transition: all 200ms ease-in; } /* 关比开快(退场要快) */
</style>实战二:列表增删(TransitionGroup)
vue
<TransitionGroup name="list" tag="ul">
<li v-for="item in items" :key="item.id">{{ item.text }}</li>
</TransitionGroup>
<style>
.list-enter-active, .list-leave-active { transition: all 300ms ease; }
.list-enter-from { opacity: 0; transform: translateX(-16px); }
.list-leave-to { opacity: 0; transform: translateX(16px); }
.list-move { transition: transform 300ms ease; } /* 其他元素平滑让位 */
</style>关键三点:tag="ul" 指定渲染成列表标签;:key 必须是稳定唯一 id(别用数组下标);.list-move 让「被删项旁边的元素」平滑补位——不加它会让位生硬。
实战三:路由切换淡入
vue
<!-- App.vue -->
<router-view v-slot="{ Component }">
<Transition name="page" mode="out-in">
<component :is="Component" />
</Transition>
</router-view>
<style>
.page-enter-active, .page-leave-active { transition: opacity .2s ease; }
.page-enter-from, .page-leave-to { opacity: 0; }
</style>mode="out-in":旧页面先退场再进新页面,避免两页同帧叠加跳动。
注意事项
四个坑
<Transition>里只能有一个根元素(v-if/v-else二选一可以)- CSS 动画用
animation而非transition时,active 类里写animation即可,Vue 会自动监听animationend - 初次渲染也想播动画:加
appear属性 - transition 写在
enter-from里不生效——它只该写「起点状态」,过渡声明写在*-active
延伸:什么时候升级到动画库
内置 Transition 覆盖 90% 场景。需要复杂时间线编排(多元素序列、滚动驱动、物理弹簧)时再考虑:
- GSAP:跨框架通用的时间线动画库,复杂编排的事实标准
- @vueuse/motion:Vue 生态的声明式动效
原则:先内置,后库。精选资源里有链接。