扫一扫分享
为 react 应用带来了前所未有的动画体验在React项目中实现动画效果,Framer Motion提供了一个全新的思路。它的优势不在于能实现什么特效,而在于如何用更简单的方式实现复杂动画。
先看看传统的做法:
/* 纯css动画 */
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.card {
animation: slideIn 0.3s ease-out;
}在React中还需要配合状态管理:
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
setIsVisible(true);
}, []);
// 在className中根据状态切换
<div className={`card ${isVisible ? 'visible' : ''}`}>
我是一张卡片
</div>现在看看Framer Motion的做法:
<motion.div
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, ease: "easeout" }}
>
我是一张卡片
</motion.div>代码清晰表达了动画的意图:从什么状态开始,到什么状态结束,如何过渡。这就是声明式编程的魅力。
不是所有场景都需要Framer Motion。过度使用反而会增加打包体积。
推荐的使用场景:
| 场景 | 推荐方案 |
|---|---|
| 简单的hover、focus效果 | CSS |
| 多个元素的串联动画 | Framer Motion |
| 拖拽、滑动等手势交互 | Framer Motion |
| 页面进出场动画 | Framer Motion |
| 复杂的滚动动画 | Framer Motion |
Framer Motion的真正价值在于简化复杂动画的开发。
<motion.div
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{ duration: 0.4 }}
>
内容
</motion.div>initial:组件挂载时的初始状态
animate:目标状态
exit:组件卸载前的退出状态(需要配合AnimatePresence使用)
Framer Motion内部维护状态树,在props变化时自动计算动画帧,比CSS transition更适合React组件生命周期。
在大型项目中,硬编码动画参数很难维护。Variants解决了这个问题:
// 定义可复用的动画组合
const cardVariants = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.3 }
},
hover: {
y: -4,
boxShadow: "0 10px 25px rgba(0,0,0,0.1)"
}
};
// 在组件中复用
<motion.div
variants={cardVariants}
initial="hidden"
animate="visible"
whileHover="hover"
>
支持Variants的组件
</motion.div>这样做的好处:
集中管理动画参数
保持整个应用的动画风格一致
减少重复代码
在实际项目中,使用Variants可以减少60%的动画相关代码。
这是Framer Motion最实用的功能之一:
<motion.div layout>
{items.map(item => (
<motion.div key={item.id} layout>
{item.name}
</motion.div>
))}
</motion.div>当数组顺序改变时,Framer Motion会自动计算每个元素的位置变化动画。不需要手动计算坐标,不需要管理CSS类名,只需要一个layout属性。
背后的原理是FLIP算法:
First:记录元素的初始位置
Last:记录元素的最终位置
Invert:计算反向变换
Play:执行动画
这种方法性能很好,因为它只改变transform属性,不触发重排。
传统的页面切换会出现白屏闪烁,使用Framer Motion可以这样解决:
// pages/dashboard/[id].js
import { AnimatePresence, motion } from 'framer-motion';
import { useRouter } from 'next/router';
export default function Dashboard({ data }) {
const router = useRouter();
return (
<AnimatePresence mode="wait">
<motion.div
key={router.asPath} // 路由变化时重新挂载
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.3 }}
>
<DashboardContent data={data} />
</motion.div>
</AnimatePresence>
);
}关键点:
mode="wait":新页面进场完成后,旧页面才退出,避免布局抖动
key={router.asPath}:确保路由切换时重新挂载组件
exit动画:旧页面平滑淡出
这样改进后,页面切换变得连贯自然,用户体验明显提升。
有些项目几乎每个元素都在动:按钮缩放、卡片旋转、文字淡入。结果用户反而觉得眼花缭乱。
正确做法: 动画应该有明确的目的:
引导用户注意力(提示新内容)
提供操作反馈(确认点击成功)
表达状态变化(显示加载进度)
不要为了炫酷而添加动画。
Framer Motion虽然强大,但也要注意性能成本:
// 错误示例:列表中每项都有复杂动画
{items.map(item => (
<motion.div
key={item.id}
animate={{
x: item.position,
rotate: item.angle,
opacity: item.visible ? 1 : 0
}}
transition={{ type: "spring", stiffness: 300 }}
>
{item.content}
</motion.div>
))}
// 如果有1000项,性能会很差正确做法:
只为关键交互元素添加动画
使用shouldReduceMotion检测用户偏好
对长列表使用虚拟滚动优化
Framer Motion和CSS动画不是对立关系,而是互补关系。
| 方面 | Framer Motion | CSS动画 |
|---|---|---|
| 学习成本 | 低(声明式) | 中等(需要理解keyframes) |
| React集成 | 很好 | 需要手动管理className |
| 复杂交互 | 强 | 弱 |
| 打包体积 | 增加约40KB | 0(浏览器原生支持) |
| 性能 | 良好(GPU加速) | 优秀(浏览器优化) |
选择标准:
简单的视觉动画用CSS
复杂的交互动画用Framer Motion
<motion.div
drag
dragConstraints={{ left: 0, right: 300 }}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
可拖拽元素
</motion.div><motion.section
initial={{ opacity: 0, y: 50 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
>
进入视口时触发动画
</motion.section>const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.1 // 子元素依次动画
}
}
};
const itemVariants = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 }
};
<motion.div
variants={containerVariants}
initial="hidden"
animate="visible"
>
<motion.div variants={itemVariants}>项目1</motion.div>
<motion.div variants={itemVariants}>项目2</motion.div>
<motion.div variants={itemVariants}>项目3</motion.div>
</motion.div>如果你还在用纯CSS或传统方式处理React动画,可能会浪费很多开发时间,而且用户体验也不够好。
Framer Motion不仅仅是动画库,它把动画从繁琐的CSS中解放出来,融入到React的组件化思维中。
一旦体验过Variants、布局动画这些功能,就很难再回到传统做法了。它让动画开发变得更简单、更高效,同时提供了更好的用户体验。
对于现代React项目来说,Framer Motion是一个值得投入时间学习的工具。
仅供个人学习参考/导航指引使用,具体请以第三方网站说明为准,本站不提供任何专业建议。如果地址失效或描述有误,请联系站长反馈~感谢您的理解与支持!
手机预览