大家好,我是FogLetter,今天我们来聊聊React中如何优雅地实现transition动画效果,让你的应用不再死气沉沉!
为什么需要动画?
在Web应用中,适当的动画效果能够:
- 提升用户体验,让界面更加生动
- 引导用户注意力
- 让状态变化更加自然
- 增加产品的专业感和精致度
React作为一个UI库,本身并不直接提供动画解决方案,但我们可以通过多种方式实现动画效果,今天重点介绍两种主流方式:CSS Transition和Framer Motion动画库。
基础款:CSS Transition
先来看一个最简单的例子 - 点击按钮展开/收起一个盒子:
import { useState } from 'react'
import styles from './box.module.css'
const Box = () => {
const [open, setOpen] = useState(false)
return (
<div>
<button onClick={() => setOpen(!open)}>
{open ? '关闭' : '打开'}
</button>
<div className={`${styles.box} ${open ? styles.open : ''}`}>
</div>
</div>
)
}
配套的CSS:
.box {
width: 100px;
height: 0;
background-color: lightblue;
transition: height 0.3s ease;
overflow: hidden;
}
.box.open {
height: 100px;
}
这里的关键点:
transition属性定义了哪些CSS属性变化时需要动画效果- 我们通过添加/移除
open类名来触发高度变化 ease是动画的时间函数,控制动画的加速度
CSS Transition的优缺点
优点:
- 简单直接,性能好(浏览器优化得好)
- 不需要额外依赖
- 适合简单的状态变化动画
缺点:
- 对于复杂动画难以管理
- 动画逻辑与组件逻辑分离
- 难以实现序列动画或交互动画
进阶款:Framer Motion
当我们需要更复杂的动画效果时,Framer Motion这个专门为React设计的动画库就派上用场了。
先看一个简单的例子:
import { motion } from 'framer-motion'
const MotionBox = () => {
return (
<motion.div
initial={{ opacity: 0, y: -50 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
style={{
backgroundColor: 'skyblue',
padding: 20
}}
>
这是一个运动的盒子
</motion.div>
)
}
这个组件会在挂载时:
- 从上方50px的位置开始(y: -50)
- 透明度从0开始
- 用0.5秒时间运动到正常位置和完全可见状态
Framer Motion的核心概念
-
motion组件:所有HTML都有对应的motion组件,如
motion.div等 -
动画状态:
initial:初始状态animate:动画结束状态exit:组件卸载时的状态(配合React的AnimatePresence使用)
-
transition配置:
duration:动画持续时间delay:延迟时间type:动画类型(spring, tween, inertia等)- 对于spring动画,还可以配置刚度(stiffness)、阻尼(damping)等物理参数
为什么选择Framer Motion?
- 声明式API:与React哲学完美契合
- 强大的动画能力:
- 关键帧动画
- 手势动画(拖拽、hover等)
- 路径动画
- 布局动画
- 优秀的性能:使用transform等硬件加速属性
- 丰富的社区支持
实战对比:两种实现方式的差异
让我们用同一个动画效果来对比两种实现方式:
需求:一个卡片,hover时放大并显示阴影
CSS实现
const Card = () => {
return (
<div className={styles.card}>
卡片内容
</div>
)
}
CSS:
.card {
width: 200px;
height: 300px;
background: white;
border-radius: 8px;
transition: all 0.3s ease;
}
.card:hover {
transform: scale(1.05);
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
}
Framer Motion实现
const MotionCard = () => {
return (
<motion.div
whileHover={{
scale: 1.05,
boxShadow: "0 10px 20px rgba(0,0,0,0.1)"
}}
transition={{ duration: 0.3 }}
style={{
width: 200,
height: 300,
background: 'white',
borderRadius: 8
}}
>
卡片内容
</motion.div>
)
}
可以看到,Framer Motion的实现更加直观,动画逻辑与组件定义在一起,而且不需要单独维护CSS类名。
更复杂的动画示例
让我们实现一个列表项的入场动画:
const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4']
const List = () => {
return (
<div>
{items.map((item, index) => (
<motion.div
key={item}
initial={{ opacity: 0, x: -50 }}
animate={{ opacity: 1, x: 0 }}
transition={{
duration: 0.5,
delay: index * 0.1
}}
style={{
padding: '10px',
margin: '5px',
background: 'lightblue'
}}
>
{item}
</motion.div>
))}
</div>
)
}
这个例子中,每个列表项会依次从左侧滑入,形成了漂亮的阶梯式动画效果。通过动态计算delay,我们只用了几行代码就实现了看起来相当专业的动画效果。
性能优化小贴士
- 优先使用transform和opacity属性做动画,这些属性不会触发重排
- 避免同时动画太多元素
- 对于列表动画,使用AnimatePresence组件管理元素的卸载动画
总结
React中的transition动画实现有多种选择:
- 简单状态变化:CSS Transition足够
- 复杂交互动画:Framer Motion是更好的选择
记住,动画的目的是提升用户体验,而不是炫技。适度使用动画能让你的应用更加生动,过度使用则会让用户感到不适。
希望这篇笔记能帮助你更好地在React中实现动画效果!如果有任何问题,欢迎在评论区留言讨论。