各位前端er!是不是经常被产品经理那句“这里能不能加点动效?”搞得头皮发麻?别慌,今天咱们就来聊聊Vue里的过渡和动画,保证让你从“动效小白”升级为“丝滑大师”!
先说实话:哪个用户不喜欢看丝滑的动效?就像喝奶茶要有珍珠,吃泡面要有火腿肠,网页没有过渡动画,总觉得少了点灵魂。但传统JS操作DOM实现动画简直反人类,好在Vue给我们准备了<transition>组件这个神器!
一、基础入门:让元素“淡入淡出”的魔法
想象一下,你要让一个div像幽灵一样缓缓出现又消失,用Vue有多简单?
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>淡入淡出示例</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
/* 进入和离开的激活期 */
.fade-enter-active, .fade-leave-active {
transition: opacity 0.5s ease;
}
/* 进入开始和离开结束的状态 */
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
</style>
</head>
<body>
<div id="app">
<button @click="show = !show">
{{ show ? '隐藏' : '显示' }}
</button>
<transition name="fade">
<div v-if="show" class="demo-box">
嘿,我淡入淡出给你看!
</div>
</transition>
</div>
<script>
const { createApp } = Vue
createApp({
data() {
return {
show: true
}
}
}).mount('#app')
</script>
</body>
</html>
保存运行,点击按钮看看?是不是丝滑得让人感动?
核心原理揭秘:Vue在元素插入或移除时,自动添加/删除特定的CSS类名,就像给元素穿脱“隐身衣”:
v-enter-from:进入动画的起点(隐身状态)v-enter-active:进入动画进行中(穿隐身衣的过程)v-enter-to:进入动画的终点(完全现身)v-leave-from:离开动画的起点(现身状态)v-leave-active:离开动画进行中(脱隐身衣的过程)v-leave-to:离开动画的终点(完全隐身)
注意上面代码中name="fade",这表示Vue会自动把类名前缀从v-换成fade-。如果你不写name,默认就是v-前缀。
二、进阶玩法:让动画更花里胡哨
只会淡入淡出太基础?来看看怎么让元素“蹦蹦跳跳”地出现:
<template>
<div id="app">
<button @click="show = !show">切换</button>
<transition name="bounce">
<div v-if="show" class="bounce-box">
我弹,我弹,我弹弹弹!
</div>
</transition>
</div>
</template>
<style>
.bounce-enter-active {
animation: bounce-in 0.8s;
}
.bounce-leave-active {
animation: bounce-in 0.8s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.2);
}
100% {
transform: scale(1);
}
}
</style>
这个效果就像皮球落地一样,先压缩再弹起,最后稳定。是不是瞬间有内味了?
三、实战案例:购物车添加商品动画
光会基础可不够,来点实际的!比如那个经典的“商品飞入购物车”效果:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>购物车动画</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
.container {
display: flex;
justify-content: space-between;
padding: 20px;
}
.product {
width: 100px;
height: 100px;
background: #4CAF50;
color: white;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.cart {
width: 60px;
height: 60px;
background: #ff9800;
color: white;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
position: relative;
}
.cart-count {
position: absolute;
top: -10px;
right: -10px;
background: red;
color: white;
border-radius: 50%;
width: 20px;
height: 20px;
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
}
.fly-enter-active {
transition: all 0.8s cubic-bezier(0.68, -0.55, 0.27, 1.55);
}
.fly-enter-from {
opacity: 0;
transform: translateX(0) translateY(0) scale(1);
}
.fly-enter-to {
opacity: 1;
transform: translateX(200px) translateY(-100px) scale(0.5);
}
</style>
</head>
<body>
<div id="app">
<div class="container">
<div class="product" @click="addToCart">
点击购买
</div>
<div class="cart">
购物车
<div class="cart-count">{{ count }}</div>
</div>
</div>
<transition name="fly" @enter="onEnter">
<div v-if="flying" class="product flying-item">+1</div>
</transition>
</div>
<script>
const { createApp } = Vue
createApp({
data() {
return {
count: 0,
flying: false
}
},
methods: {
addToCart() {
this.flying = true
this.count++
},
onEnter() {
setTimeout(() => {
this.flying = false
}, 800)
}
}
}).mount('#app')
</script>
</body>
</html>
这个例子中,点击商品时会创建一个“+1”元素,沿着曲线飞入购物车,同时购物车数量更新。用的cubic-bezier缓动函数让飞行轨迹更有“抛物体”的感觉。
四、终极武器:JavaScript钩子实现复杂动画
当CSS无法满足你的骚操作时,JavaScript钩子就该登场了!
<template>
<div id="app">
<button @click="show = !show">复杂动画切换</button>
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
@enter-cancelled="enterCancelled"
@before-leave="beforeLeave"
@leave="leave"
@after-leave="afterLeave"
@leave-cancelled="leaveCancelled"
:css="false"
>
<div v-if="show" class="js-animation-box">
我被JS控制的!
</div>
</transition>
</div>
</template>
<script>
import { gsap } from 'gsap' // 假设引入了GSAP动画库
export default {
data() {
return {
show: false
}
},
methods: {
beforeEnter(el) {
console.log('动画开始前:设置初始状态')
el.style.opacity = 0
el.style.transform = 'scale(0) rotate(0deg)'
},
enter(el, done) {
console.log('进入动画进行中')
gsap.to(el, {
duration: 1,
opacity: 1,
scale: 1,
rotation: 360,
ease: 'back.out(1.7)',
onComplete: done
})
},
afterEnter(el) {
console.log('进入动画完成')
},
enterCancelled(el) {
console.log('进入动画被取消')
},
beforeLeave(el) {
console.log('离开动画开始前')
},
leave(el, done) {
console.log('离开动画进行中')
gsap.to(el, {
duration: 0.5,
opacity: 0,
scale: 0,
rotation: -360,
ease: 'power2.in',
onComplete: done
})
},
afterLeave(el) {
console.log('离开动画完成')
},
leaveCancelled(el) {
console.log('离开动画被取消')
}
}
}
</script>
这个例子展示了所有JavaScript钩子,用GSAP库实现了一个带弹性效果的旋转动画。注意:css="false"是告诉Vue“别插手CSS动画,全权交给JS处理”!
五、避坑指南与性能优化
动画虽好,可不要贪杯哦!以下几点一定要注意:
- 性能优先:尽量使用
transform和opacity做动画,这两个属性不会触发重排 - 硬件加速:可以尝试
transform: translateZ(0)开启GPU加速 - 避免过度:不是所有东西都需要动画,关键操作反馈和状态变化就够了
- 移动端适配:移动设备性能有限,动画要更简洁
常见踩坑:
- 忘记写
name属性,然后奇怪为什么CSS不生效 - 没设置初始状态,动画直接从中间开始
- 没调用
done回调,导致钩子函数卡住
结语
好了,看到这里你已经掌握了Vue单元素/组件过渡动画的精髓!从基础的CSS过渡到复杂的JavaScript钩子,现在你完全可以在项目中大展身手了。
记住,好的动画应该是“润物细无声”的——用户可能说不出来哪里好,但就是觉得用着舒服。就像那句老话:最好的界面是用户感觉不到的界面。
快去给你的网页加点魔法吧!如果还有问题,Vue官方文档永远是你最好的朋友(虽然有时候有点难懂,但现在你应该都能看明白了)!
彩蛋:试试把今天学到的技术组合使用,比如先CSS过渡再JS动画,或者给不同状态设置不同的缓动函数,说不定能创造出下一个让人惊艳的动效呢!
附:完整示例代码合集
本文所有示例均可直接复制到HTML文件中运行,建议边看边动手试试。动画这东西,光看不练假把式,动手敲一遍,理解更深!

被折叠的 条评论
为什么被折叠?



