Vue.js 过渡 & 动画(千字长文)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

在现代 Web 开发中,过渡与动画是提升用户体验的重要工具。Vue.js 作为一款流行的前端框架,提供了开箱即用的过渡系统,让开发者能够轻松实现优雅的视觉效果。无论是简单的元素显示/隐藏动画,还是复杂的列表增删操作的平滑过渡,Vue.js 的过渡与动画功能都能通过简洁的 API 和灵活的配置实现。本文将从基础概念出发,结合实际案例,逐步讲解如何在 Vue.js 中实现过渡与动画效果,并探索进阶技巧。


过渡系统基础:Vue.js 的内置过渡功能

Vue.js 的过渡系统基于 CSS 过渡和动画,通过 transition 组件和 transition-group 组件实现。其核心思想是:通过在元素切换时自动添加、移除 CSS 类名,触发预定义的样式变化。

过渡类名的生命周期

Vue.js 会为元素在不同状态自动添加以下类名:
| 状态 | 类名前缀 | 作用说明 |
|---------------------|---------------|-----------------------------------|
| 进入过渡开始前 | v-enter-from| 元素初始状态(仅 CSS 过渡有效) |
| 进入过渡激活时 | v-enter-active| 过渡激活时的样式覆盖 |
| 进入过渡结束时 | v-enter-to | 过渡最终状态 |
| 离开过渡开始前 | v-leave-from | 离开前的初始状态 |
| 离开过渡激活时 | v-leave-active| 过渡激活时的样式覆盖 |
| 离开过渡结束时 | v-leave-to | 离开后的最终状态 |

示例:简单按钮点击切换动画

<template>  
  <div>  
    <button @click="show = !show">Toggle</button>  
    <transition name="fade">  
      <p v-if="show">Hello, Vue.js Transition!</p>  
    </transition>  
  </div>  
</template>  

<script setup>  
import { ref } from 'vue';  
const show = ref(true);  
</script>  

<style>  
.fade-enter-from {  
  opacity: 0;  
}  
.fade-enter-active {  
  transition: opacity 0.5s ease-out;  
}  
.fade-leave-to {  
  opacity: 0;  
}  
.fade-leave-active {  
  transition: opacity 0.3s ease-in;  
}  
</style>  

解释

  • 当元素首次显示时,fade-enter-from 设置初始透明度为 0,fade-enter-active 定义过渡效果。
  • 离开时,fade-leave-to 将透明度变为 0,fade-leave-active 控制过渡时间。

进入与离开过渡的协同设计

过渡效果通常需要同时处理元素的进入(v-ifv-show 切换为 true)和离开(切换为 false)。通过合理设置 CSS 属性,可以实现更自然的视觉效果。

案例:元素的平滑滑动

<template>  
  <div>  
    <button @click="toggle = !toggle">Slide Toggle</button>  
    <transition name="slide">  
      <div v-if="toggle" class="box">Slide Me!</div>  
    </transition>  
  </div>  
</template>  

<script setup>  
import { ref } from 'vue';  
const toggle = ref(false);  
</script>  

<style>  
.box {  
  width: 100px;  
  height: 100px;  
  background: #4CAF50;  
}  
.slide-enter-from,  
.slide-leave-to {  
  transform: translateX(-100%);  
}  
.slide-enter-active,  
.slide-leave-active {  
  transition: transform 0.5s ease;  
}  
</style>  

关键点

  • transform 属性比直接修改 leftmargin 更适合动画,因其由 GPU 加速,性能更优。
  • slide-enter-fromslide-leave-totransform 值相反,形成双向滑动效果。

列表与动画的结合:过渡组的使用

当列表项动态增删时,transition-group 组件可以为每个子元素添加唯一 key,并实现平滑过渡。

案例:待办事项列表的增删动画

<template>  
  <div>  
    <input v-model="newTodo" @keyup.enter="addTodo" placeholder="Add a todo" />  
    <transition-group name="list" tag="ul">  
      <li v-for="todo in todos" :key="todo.id" @click="removeTodo(todo.id)">  
        {{ todo.text }}  
      </li>  
    </transition-group>  
  </div>  
</template>  

<script setup>  
import { ref } from 'vue';  
const newTodo = ref('');  
const todos = ref([]);  

const addTodo = () => {  
  if (newTodo.value.trim()) {  
    todos.value.push({  
      id: Date.now(),  
      text: newTodo.value,  
    });  
    newTodo.value = '';  
  }  
};  

const removeTodo = (id) => {  
  todos.value = todos.value.filter(todo => todo.id !== id);  
};  
</script>  

<style>  
.list-enter-from,  
.list-leave-to {  
  opacity: 0;  
  transform: translateY(30px);  
}  
.list-enter-active,  
.list-leave-active {  
  transition: all 0.3s ease;  
}  
.list-leave-active {  
  position: absolute;  
}  
</style>  

技巧说明

  • position: absolute 在离开过渡时避免布局抖动,因元素离开时仍占据空间。
  • transform 结合 opacity 实现更立体的过渡效果。

自定义动画:结合 JavaScript 钩子函数

Vue.js 过渡系统支持通过 @before-enter@enter 等钩子函数,直接操作 DOM 或使用 JavaScript 动画库(如 GSAP)。

案例:使用 GSAP 实现复杂动画

<template>  
  <div>  
    <button @click="animate = !animate">Animate</button>  
    <transition  
      @before-enter="beforeEnter"  
      @enter="enter"  
      @after-enter="afterEnter"  
      @leave="leave"  
    >  
      <div v-if="animate" class="box">GSAP Animation</div>  
    </transition>  
  </div>  
</template>  

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

const animate = ref(false);  

const beforeEnter = (el) => {  
  el.style.opacity = 0;  
  el.style.transform = 'scale(0.5)';  
};  

const enter = (el, done) => {  
  gsap.to(el, {  
    opacity: 1,  
    scale: 1,  
    rotation: 360,  
    duration: 1,  
    onComplete: done, // 动画完成后调用 done()  
  });  
};  

const leave = (el, done) => {  
  gsap.to(el, {  
    opacity: 0,  
    scale: 0.5,  
    rotation: -180,  
    duration: 0.5,  
    onComplete: done,  
  });  
};  

const afterEnter = () => {  
  console.log('Animation completed!');  
};  
</script>  

<style>  
.box {  
  width: 150px;  
  height: 150px;  
  background: #2196F3;  
  transition: none; /* 禁用 CSS 过渡,避免冲突 */  
}  
</style>  

关键点

  • done 回调是必须的,用于告知 Vue 动画已完成。
  • 通过 GSAP 的 rotation 属性,可实现元素旋转效果。

第三方动画库的集成:animate.css 的使用

animate.css 是一个流行的 CSS 动画库,与 Vue.js 结合可快速实现丰富效果。

案例:用 animate.css 实现弹跳进入动画

<template>  
  <div>  
    <button @click="show = !show">Bounce Animation</button>  
    <transition  
      name="animate__animated animate__bounce"  
      enter-active-class="animate__bounceIn"  
      leave-active-class="animate__bounceOut"  
    >  
      <div v-if="show" class="box">Bounce Me!</div>  
    </transition>  
  </div>  
</template>  

<script setup>  
import { ref } from 'vue';  
const show = ref(false);  
</script>  

<style>  
.box {  
  width: 120px;  
  height: 120px;  
  background: #FF5722;  
}  
/* 引入 animate.css 样式 */  
@import url("https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css");  
</style>  

说明

  • 通过 enter-active-classleave-active-class 指定 animate.css 的动画类名。
  • animate__animated 是 animate.css 的基础类,需与具体动画类组合使用。

进阶技巧:过渡模式与条件渲染

1. 过渡模式(mode 属性)

Vue.js 的 transition 组件支持 mode 属性控制过渡顺序:

  • in-out:新元素先完成过渡,旧元素再离开。
  • out-in:旧元素先离开,新元素再进入。

示例

<transition mode="out-in">  
  <div :key="view">Current View: {{ view }}</div>  
</transition>  

2. 条件渲染与过渡结合

通过 v-ifv-show 的组合,可实现更精细的控制。例如,使用 v-show 处理高频切换,避免 DOM 重渲染:

<transition name="fade">  
  <div v-if="show" v-show="isVisible">Content</div>  
</transition>  

结论

Vue.js 的过渡与动画系统提供了从基础到高级的完整解决方案,开发者可以通过 CSS、JavaScript 钩子或第三方库灵活实现需求。无论是简单的元素淡入淡出,还是复杂的列表增删动画,Vue.js 的设计都强调了代码的简洁性与可维护性。掌握这些技巧后,不仅能提升应用的交互体验,还能在项目中快速实现视觉化反馈,增强用户的参与感。

实践建议

  1. 从基础 CSS 过渡开始,逐步尝试复杂动画。
  2. 使用 Chrome DevTools 的“Elements”面板观察过渡类名的添加/移除过程。
  3. 结合 @vue/devtools 插件调试过渡效果。

通过本文的学习,希望读者能够将 Vue.js 的过渡与动画能力融入实际项目中,创造出更具吸引力的 Web 应用。

最新发布