让React组件"动"起来 - Transition动画完全指南

280 阅读4分钟

大家好,我是FogLetter,今天我们来聊聊React中如何优雅地实现transition动画效果,让你的应用不再死气沉沉!

为什么需要动画?

在Web应用中,适当的动画效果能够:

  1. 提升用户体验,让界面更加生动
  2. 引导用户注意力
  3. 让状态变化更加自然
  4. 增加产品的专业感和精致度

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>
    )
}

这个组件会在挂载时:

  1. 从上方50px的位置开始(y: -50)
  2. 透明度从0开始
  3. 用0.5秒时间运动到正常位置和完全可见状态

Framer Motion的核心概念

  1. motion组件:所有HTML都有对应的motion组件,如motion.div

  2. 动画状态

    • initial:初始状态
    • animate:动画结束状态
    • exit:组件卸载时的状态(配合React的AnimatePresence使用)
  3. transition配置

    • duration:动画持续时间
    • delay:延迟时间
    • type:动画类型(spring, tween, inertia等)
    • 对于spring动画,还可以配置刚度(stiffness)、阻尼(damping)等物理参数

为什么选择Framer Motion?

  1. 声明式API:与React哲学完美契合
  2. 强大的动画能力
    • 关键帧动画
    • 手势动画(拖拽、hover等)
    • 路径动画
    • 布局动画
  3. 优秀的性能:使用transform等硬件加速属性
  4. 丰富的社区支持

实战对比:两种实现方式的差异

让我们用同一个动画效果来对比两种实现方式:

需求:一个卡片,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,我们只用了几行代码就实现了看起来相当专业的动画效果。

性能优化小贴士

  1. 优先使用transform和opacity属性做动画,这些属性不会触发重排
  2. 避免同时动画太多元素
  3. 对于列表动画,使用AnimatePresence组件管理元素的卸载动画

总结

React中的transition动画实现有多种选择:

  • 简单状态变化:CSS Transition足够
  • 复杂交互动画:Framer Motion是更好的选择

记住,动画的目的是提升用户体验,而不是炫技。适度使用动画能让你的应用更加生动,过度使用则会让用户感到不适。

希望这篇笔记能帮助你更好地在React中实现动画效果!如果有任何问题,欢迎在评论区留言讨论。