🎬 引言:为什么选择Framer Motion?
在React生态系统中,动画一直是个有点棘手的话题。传统的CSS动画虽然强大,但与React组件的生命周期配合起来总有些不够"React式"的感觉。这就是Framer Motion的用武之地!它是一个专为React设计的动画库,让你可以用声明式的方式创建流畅的交互体验。
import { motion } from "framer-motion"
<motion.div
animate={{ x: 100 }}
transition={{ duration: 0.5 }}
/>
简单一行代码就能实现平滑的移动动画!✨
🛠️ 安装与基础使用
1. 安装
npm install framer-motion
# 或
yarn add framer-motion
2. 基本动画
Framer Motion的核心是motion组件,它是常规HTML/SVG元素的动画版本。
import { motion } from "framer-motion"
function MyComponent() {
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 1 }}
>
Hello Framer Motion!
</motion.div>
)
}
initial: 初始状态animate: 动画结束状态transition: 动画过渡配置
🎨 与常规CSS动画的区别
| 特性 | Framer Motion 🚀 | 常规CSS 🎨 |
|---|---|---|
| 语法 | 声明式,与React集成 | 命令式,独立于组件 |
| 状态管理 | 自动处理组件挂载/卸载 | 需要手动处理 |
| 复杂动画 | 简单易实现(如路径动画) | 需要大量关键帧 |
| 物理动画 | 内置弹簧物理效果 | 需要自定义贝塞尔曲线 |
| 手势支持 | 内置拖拽、悬停等 | 需要JavaScript辅助 |
| 性能 | 使用硬件加速 | 依赖浏览器优化 |
🌈 进阶功能
1. 手势交互
<motion.button
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
>
点击我!
</motion.button>
2. 关键帧动画
<motion.div
style={{
width: 100,
height: 100,
background: "#ff0000", // 初始颜色
}}
animate={{
x: [0, 100, 0],
opacity: [0.5, 1, 0.5, 1],
backgroundColor: ['#ff0000', '#00ff00', '#0000ff'],
}}
transition={{
duration: 3,
repeat: Infinity,
}}
/>
3. 路径动画
<motion.div
animate={{
x: "calc(100vw - 100px)",
y: [0, -50, 0]
}}
transition={{
duration: 2,
repeat: Infinity
}}
/>
🧩 与React状态集成
Framer Motion可以无缝与React状态配合:
function ToggleBox() {
const [isOn, setIsOn] = useState(false)
return (
<motion.div
layout
style={{
background: isOn ? "#00ff00" : "#ff0000",
borderRadius: "50%",
width: 100,
height: 100
}}
onClick={() => setIsOn(!isOn)}
/>
)
}
注意layout属性让尺寸/位置变化自动动画化!🎉
🎉Framer Motion中一些常见的属性
Framer Motion 是一个流行的 React 动画库,提供了丰富的属性和组件来创建流畅的交互式动画。以下是一些常用的 Framer Motion 属性及其用途:
1. 基础动画属性
-
animate
定义组件的目标动画状态(如{ opacity: 1, x: 0 }),通常与initial配对使用。<motion.div animate={{ scale: 1.2 }} /> -
initial
设置动画的初始状态(如{ opacity: 0 })。<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} /> -
exit
定义组件卸载时的退出动画(需配合 React 的<AnimatePresence>使用)。<AnimatePresence> {isVisible && <motion.div exit={{ opacity: 0 }} />} </AnimatePresence>
2. 交互动画属性
-
whileHover
鼠标悬停时触发的动画(如缩放、颜色变化)。<motion.button whileHover={{ scale: 1.05 }} /> -
whileTap
点击/按压时触发的动画(模拟按钮按下效果)。<motion.div whileTap={{ scale: 0.9 }} /> -
whileFocus
元素获得焦点时的动画(适用于输入框)。 -
whileDrag
拖拽过程中的动画效果(需配合drag属性)。
3. 布局动画
-
layout
自动平滑过渡组件布局变化(如位置、尺寸调整)。<motion.div layout style={{ width: isOpen ? "200px" : "100px" }} /> -
layoutId
共享布局 ID,实现跨组件的无缝过渡(如模态框切换)。<motion.div layoutId="unique-id" />
4. 滚动动画
-
whileInView
当元素进入视口时触发动画(需设置viewport配置)。<motion.section whileInView={{ opacity: 1 }} viewport={{ once: true }} /> -
viewport
控制视口检测的配置(如margin、once等)。
5. 拖拽功能
-
drag
启用拖拽(true或方向"x"/"y")。<motion.div drag="x" dragConstraints={{ left: 0, right: 100 }} /> -
dragConstraints
限制拖拽边界(如{ left: 0, right: 0 })。 -
dragElastic
拖拽边界弹性系数(默认0.5)。
6. 过渡配置
-
transition
自定义动画过渡参数(如时长、缓动曲线)。<motion.div animate={{ x: 100 }} transition={{ type: "spring", damping: 10 }} /> -
type
过渡类型("spring"、"tween"、"inertia")。 -
staggerChildren
子元素的交错动画延迟(用于容器组件)。
7. 高级属性
-
variants
预定义动画状态组,简化复杂动画逻辑。const variants = { hidden: { opacity: 0 }, visible: { opacity: 1 } }; <motion.div variants={variants} initial="hidden" animate="visible" /> -
custom
传递动态参数给variants动画。 -
animateChildren
控制子元素是否继承父组件的动画。
8. SVG 动画
pathLength
SVG 路径绘制动画(范围0到1)。<motion.path animate={{ pathLength: 1 }} />
9. 其他实用属性
style
支持动态 CSS 变量(如--color)。onAnimationComplete
动画完成时的回调函数。
何时使用?
- 微交互:按钮悬停(
whileHover)、点击反馈(whileTap)。 - 页面过渡:路由切换(
AnimatePresence+exit)。 - 加载效果:元素入场(
initial+animate)。 - 响应滚动:视口触发动画(
whileInView)。
Framer Motion 的详细文档可参考:www.framer.com/motion
🚀 性能小贴士
- 优先使用
transform(scale, rotate, translate)而非直接修改width/height - 对复杂动画使用
will-change: transformCSS属性 - 避免在列表项中使用大量同时运行的动画
- 使用
AnimatePresence处理组件卸载动画
🔮 结语
Framer Motion为React带来了前所未有的动画体验,让创建专业级交互动画变得简单直观。它不仅仅是CSS动画的替代品,而是一套完整的动画思维模式。从简单的淡入淡出到复杂的用户交互流程,Framer Motion都能优雅处理。
现在就去尝试吧,让你的React应用动起来!💫
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
你的动画之旅从此开始!
</motion.div>