在前端開發中,生硬的頁面切換、毫無反饋的操作響應,往往會讓用户體驗大打折扣。想象一下:點擊按鈕後內容突然出現、刪除列表項時元素瞬間消失、路由切換時頁面卡頓跳轉——這些場景都會讓應用顯得“機械又冰冷”。

Vue 內置的過渡動畫系統,能輕鬆解決這些問題。它無需複雜的第三方庫(當然也支持集成),通過簡單的組件封裝和配置,就能實現流暢的動畫效果,讓應用交互更具質感。本文結合實際開發場景,從基礎到進階,帶你掌握 Vue 過渡動畫的核心用法,讓你的項目從“能用”升級到“好用”。

一、基礎入門:5分鐘實現元素淡入淡出

Vue 提供了 <transition> 組件,專門用於包裹單個元素/組件的顯示與隱藏過渡。它的核心原理是:在元素狀態變化時(如 v-ifv-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-classleave-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:縮放進入

只需替換類名,就能快速切換動畫效果,開發效率大幅提升。

五、實戰避坑指南

  1. 避免動畫閃爍:初始渲染時,若元素默認顯示(v-if="true"),可能會出現閃爍。可添加 appear 屬性,讓初始渲染也觸發動畫:

    <transition name="fade" appear>
      <div class="alert-box">初始渲染動畫</div>
    </transition>
    
  2. 性能優化:儘量使用 transformopacity 做動畫,這兩個屬性不會觸發瀏覽器重排(reflow),性能更好;避免使用 widthheightmargin 等屬性做動畫。

  3. 長列表動畫優化:對於超過 100 項的長列表,避免使用 <transition-group> 做逐元素動畫,會導致性能下降。可採用“虛擬列表”+ 局部動畫的方式,只對可見元素做動畫。

  4. 移動端適配:移動端動畫時長建議控制在 0.2~0.3 秒,過長會讓用户覺得卡頓;同時避免同時觸發多個元素動畫,減少主線程壓力。

  5. 條件渲染注意:使用 v-if 時,元素會被銷燬/重建,動畫觸發正常;使用 v-show 時,元素僅隱藏(display: none),同樣支持過渡動畫,但需注意初始狀態。