在前端開發中,生硬的頁面切換、毫無反饋的操作響應,往往會讓用户體驗大打折扣。想象一下:點擊按鈕後內容突然出現、刪除列表項時元素瞬間消失、路由切換時頁面卡頓跳轉——這些場景都會讓應用顯得“機械又冰冷”。
Vue 內置的過渡動畫系統,能輕鬆解決這些問題。它無需複雜的第三方庫(當然也支持集成),通過簡單的組件封裝和配置,就能實現流暢的動畫效果,讓應用交互更具質感。本文結合實際開發場景,從基礎到進階,帶你掌握 Vue 過渡動畫的核心用法,讓你的項目從“能用”升級到“好用”。
一、基礎入門:5分鐘實現元素淡入淡出
Vue 提供了 <transition> 組件,專門用於包裹單個元素/組件的顯示與隱藏過渡。它的核心原理是:在元素狀態變化時(如 v-if、v-show 切換),自動添加/移除一系列 CSS 類,從而觸發動畫。
1. 核心用法:CSS 過渡實現淡入淡出
這是最常用的基礎場景,比如模態框顯示/隱藏、提示消息彈出等。
<template>
<div class="demo-container">
<button @click="isShow = !isShow" class="btn">切換提示框</button>
<!-- 用transition包裹需要動畫的元素,指定name屬性 -->
<transition name="fade">
<div v-if="isShow" class="alert-box">
操作成功!數據已保存~
</div>
</transition>
</div>
</template>
<script>
export default {
data() {
return {
isShow: false
}
}
}
</script>
<style scoped>
.btn {
padding: 8px 16px;
background: #42b983;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.alert-box {
margin-top: 16px;
padding: 12px;
background: #f0f9eb;
color: #389e0d;
border-radius: 4px;
}
/* 進入動畫:從透明到不透明,從下到上 */
.fade-enter-active {
transition: all 0.3s ease; /* 動畫時長和緩動效果 */
}
/* 進入開始狀態 */
.fade-enter {
opacity: 0; /* 透明 */
transform: translateY(20px); /* 向下偏移20px */
}
/* 離開動畫:從不透明到透明,從上到下 */
.fade-leave-active {
transition: all 0.3s ease;
}
/* 離開結束狀態 */
.fade-leave-to {
opacity: 0;
transform: translateY(-20px);
}
</style>
2. 關鍵原理:Vue 自動添加的 CSS 類
當元素狀態變化時,Vue 會按順序添加以下類(以 name="fade" 為例):
- 進入階段:
fade-enter(開始)→fade-enter-active(過程)→fade-enter-to(結束) - 離開階段:
fade-leave(開始)→fade-leave-active(過程)→fade-leave-to(結束)
其中,-active 類用於定義動畫的持續時間、緩動函數等;-enter/-leave-to 定義動畫的初始狀態;-enter-to/-leave 定義動畫的結束狀態(可省略,默認繼承元素本身狀態)。
二、進階用法:讓動畫更豐富
基礎的淡入淡出滿足不了複雜場景?試試 CSS 動畫、列表過渡,讓交互更有層次感。
1. CSS 動畫:實現複雜動效(如彈跳、翻轉)
CSS 動畫比過渡更靈活,支持關鍵幀動畫,適合實現彈跳、翻轉、縮放等複雜效果。用法與過渡類似,只需在 -active 類中定義 animation 屬性。
<template>
<div class="demo-container">
<button @click="isShow = !isShow" class="btn">彈出通知</button>
<transition name="bounce">
<div v-if="isShow" class="notify-box">
📢 新消息提醒:您有一條待處理任務
</div>
</transition>
</div>
</template>
<style scoped>
.notify-box {
margin-top: 16px;
padding: 12px;
background: #fff7e6;
color: #faad14;
border-radius: 4px;
display: inline-block;
}
/* 進入動畫:彈跳效果 */
.bounce-enter-active {
animation: bounce-in 0.5s;
}
/* 離開動畫:反向彈跳 */
.bounce-leave-active {
animation: bounce-in 0.5s reverse;
}
/* 定義關鍵幀動畫 */
@keyframes bounce-in {
0% {
transform: scale(0); /* 初始縮小到0 */
opacity: 0;
}
50% {
transform: scale(1.1); /* 中間放大到1.1 */
opacity: 1;
}
100% {
transform: scale(1); /* 最終恢復原大小 */
}
}
</style>
這種效果適合重要提示、通知彈窗等場景,能快速吸引用户注意力。
2. 列表過渡:處理數組增刪改查動畫
實際項目中,列表操作(添加、刪除、排序)非常頻繁。Vue 提供 <transition-group> 組件,專門用於列表過渡,支持批量元素的動畫效果。
注意:列表過渡必須滿足兩個條件:① 每個列表項必須有唯一的 key;② 組件默認渲染為 <span>,可通過 tag 屬性指定為 <ul>、<div> 等標籤。
<template>
<div class="demo-container">
<div class="btn-group">
<button @click="addItem" class="btn">添加項目</button>
<button @click="removeItem" class="btn btn-danger">刪除最後一項</button>
</div>
<!-- 列表過渡組件,指定tag為ul -->
<transition-group name="list" tag="ul" class="list-container">
<li v-for="item in list" :key="item.id" class="list-item">
{{ item.name }}
</li>
</transition-group>
</div>
</template>
<script>
export default {
data() {
return {
list: [
{ id: 1, name: "完成Vue動畫學習" },
{ id: 2, name: "編寫實戰案例" },
{ id: 3, name: "優化項目交互" }
],
nextId: 4
}
},
methods: {
addItem() {
this.list.push({
id: this.nextId++,
name: `新任務 ${this.nextId}`
});
},
removeItem() {
this.list.pop();
}
}
}
</script>
<style scoped>
.btn-group {
margin-bottom: 16px;
}
.btn-danger {
background: #ff4d4f;
margin-left: 8px;
}
.list-container {
list-style: none;
padding: 0;
}
.list-item {
padding: 10px;
margin: 8px 0;
background: #f5f5f5;
border-left: 4px solid #42b983;
border-radius: 4px;
}
/* 列表項進入/離開動畫 */
.list-enter-active, .list-leave-active {
transition: all 0.3s ease;
}
.list-enter {
opacity: 0;
transform: translateX(30px); /* 從右側滑入 */
}
.list-leave-to {
opacity: 0;
transform: translateX(-30px); /* 向左側滑出 */
}
/* 解決刪除時元素位置跳動問題:設置絕對定位 */
.list-leave-active {
position: absolute;
width: calc(100% - 20px);
}
</style>
3. 路由過渡:讓頁面切換更流暢
路由切換時的生硬跳轉,是很多應用的常見問題。通過給 <router-view> 包裹 <transition> 組件,就能實現頁面間的平滑過渡。
<!-- App.vue 中 -->
<template>
<div id="app">
<router-link to="/home" class="nav-link">首頁</router-link>
<router-link to="/about" class="nav-link">關於我們</router-link>
<!-- 路由過渡:淡入淡出效果 -->
<transition name="route-fade">
<router-view />
</transition>
</div>
</template>
<style>
/* 路由過渡樣式(全局樣式,無需scoped) */
.route-fade-enter-active, .route-fade-leave-active {
transition: opacity 0.5s ease;
}
.route-fade-enter, .route-fade-leave-to {
opacity: 0;
}
.nav-link {
margin: 0 10px;
text-decoration: none;
color: #42b983;
}
</style>
這種效果適合大多數場景,若想更炫酷,還可以結合 transform 實現頁面滑動、縮放等過渡。
三、高級技巧:JavaScript 鈎子實現複雜動畫
當 CSS 動畫滿足不了需求(如依賴數據計算、多步驟動畫、結合第三方庫)時,Vue 提供的 JavaScript 鈎子函數就能派上用場。
通過綁定 @before-enter、@enter、@leave 等事件,可在動畫的不同階段執行自定義邏輯,實現更靈活的控制。
示例:多步驟動畫(縮放 + 旋轉)
<template>
<div class="demo-container">
<button @click="isShow = !isShow" class="btn">觸發複雜動畫</button>
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
@before-leave="beforeLeave"
@leave="leave"
>
<div v-if="isShow" class="box"></div>
</transition>
</div>
</template>
<script>
export default {
data() {
return {
isShow: false
}
},
methods: {
// 進入動畫前:初始化樣式
beforeEnter(el) {
el.style.opacity = 0;
el.style.transform = "scale(0) rotate(0deg)";
},
// 進入動畫中:執行多步驟動畫
enter(el, done) {
// 第一步:縮放至1.2倍,顯示
el.style.transition = "all 0.3s ease";
setTimeout(() => {
el.style.opacity = 1;
el.style.transform = "scale(1.2) rotate(90deg)";
// 第二步:縮放回1倍,旋轉180度
setTimeout(() => {
el.style.transform = "scale(1) rotate(180deg)";
done(); // 動畫完成後必須調用done(),告知Vue
}, 300);
}, 0);
},
// 進入動畫後:可選回調
afterEnter(el) {
console.log("進入動畫完成!");
},
// 離開動畫前:初始化樣式
beforeLeave(el) {
el.style.opacity = 1;
el.style.transform = "scale(1) rotate(180deg)";
},
// 離開動畫中:反向執行
leave(el, done) {
el.style.transition = "all 0.3s ease";
el.style.opacity = 0;
el.style.transform = "scale(0) rotate(0deg)";
setTimeout(done, 300);
}
}
}
</script>
<style scoped>
.box {
width: 100px;
height: 100px;
background: linear-gradient(45deg, #667eea, #764ba2);
border-radius: 8px;
margin-top: 16px;
}
</style>
關鍵注意:@enter 和 @leave 鈎子中,必須調用 done() 函數,告知 Vue 動畫已完成,否則 Vue 會一直等待,導致後續邏輯阻塞。
四、懶人福音:集成第三方動畫庫
如果不想手寫 CSS 動畫,可直接集成成熟的第三方庫(如 Animate.css),一鍵實現炫酷效果。Animate.css 提供了 70+ 種現成動畫,涵蓋淡入、彈跳、翻轉、縮放等,用法簡單。
1. 安裝與引入
# 安裝Animate.css
npm install animate.css --save
在 Vue 項目入口文件(如 main.js)中引入:
import 'animate.css'; // 引入全局樣式
2. 結合 Vue 過渡使用
通過 enter-active-class 和 leave-active-class 屬性,直接指定 Animate.css 的動畫類名:
<template>
<div class="demo-container">
<button @click="isShow = !isShow" class="btn">來點炫酷的!</button>
<transition
enter-active-class="animate__animated animate__bounceInDown"
leave-active-class="animate__animated animate__bounceOutUp"
>
<div v-if="isShow" class="card">
我是炫酷動畫卡片~
</div>
</transition>
</div>
</template>
<script>
export default {
data() {
return {
isShow: false
}
}
}
</script>
<style scoped>
.card {
width: 200px;
height: 150px;
margin-top: 16px;
background: #42b983;
color: white;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
font-size: 18px;
}
</style>
常用動畫類名:
animate__fadeIn:淡入animate__slideInLeft:從左側滑入animate__flip:翻轉animate__zoomIn:縮放進入
只需替換類名,就能快速切換動畫效果,開發效率大幅提升。
五、實戰避坑指南
-
避免動畫閃爍:初始渲染時,若元素默認顯示(
v-if="true"),可能會出現閃爍。可添加appear屬性,讓初始渲染也觸發動畫:<transition name="fade" appear> <div class="alert-box">初始渲染動畫</div> </transition> -
性能優化:儘量使用
transform和opacity做動畫,這兩個屬性不會觸發瀏覽器重排(reflow),性能更好;避免使用width、height、margin等屬性做動畫。 -
長列表動畫優化:對於超過 100 項的長列表,避免使用
<transition-group>做逐元素動畫,會導致性能下降。可採用“虛擬列表”+ 局部動畫的方式,只對可見元素做動畫。 -
移動端適配:移動端動畫時長建議控制在 0.2~0.3 秒,過長會讓用户覺得卡頓;同時避免同時觸發多個元素動畫,減少主線程壓力。
-
條件渲染注意:使用
v-if時,元素會被銷燬/重建,動畫觸發正常;使用v-show時,元素僅隱藏(display: none),同樣支持過渡動畫,但需注意初始狀態。