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-if
或 v-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
属性比直接修改left
或margin
更适合动画,因其由 GPU 加速,性能更优。slide-enter-from
和slide-leave-to
的transform
值相反,形成双向滑动效果。
列表与动画的结合:过渡组的使用
当列表项动态增删时,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-class
和leave-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-if
和 v-show
的组合,可实现更精细的控制。例如,使用 v-show
处理高频切换,避免 DOM 重渲染:
<transition name="fade">
<div v-if="show" v-show="isVisible">Content</div>
</transition>
结论
Vue.js 的过渡与动画系统提供了从基础到高级的完整解决方案,开发者可以通过 CSS、JavaScript 钩子或第三方库灵活实现需求。无论是简单的元素淡入淡出,还是复杂的列表增删动画,Vue.js 的设计都强调了代码的简洁性与可维护性。掌握这些技巧后,不仅能提升应用的交互体验,还能在项目中快速实现视觉化反馈,增强用户的参与感。
实践建议:
- 从基础 CSS 过渡开始,逐步尝试复杂动画。
- 使用 Chrome DevTools 的“Elements”面板观察过渡类名的添加/移除过程。
- 结合
@vue/devtools
插件调试过渡效果。
通过本文的学习,希望读者能够将 Vue.js 的过渡与动画能力融入实际项目中,创造出更具吸引力的 Web 应用。