name: framer-motion
description: 用于React的综合性Framer Motion动画库。涵盖运动组件、变体、手势、页面过渡和滚动动画。适用于为React/Next.js应用程序添加动画效果。
Framer Motion 技能
用于React应用程序的生产就绪动画。
快速开始
安装
npm install framer-motion
# 或
pnpm add framer-motion
基本用法
import { motion } from "framer-motion";
// 简单动画
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
>
内容
</motion.div>
核心概念
示例
模板
快速参考
基本动画
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.3 }}
>
内容
</motion.div>
悬停与点击
<motion.button
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
transition={{ type: "spring", stiffness: 400, damping: 17 }}
>
点击我
</motion.button>
变体
const container = {
hidden: { opacity: 0 },
show: {
opacity: 1,
transition: { staggerChildren: 0.1 }
}
};
const item = {
hidden: { opacity: 0, y: 20 },
show: { opacity: 1, y: 0 }
};
<motion.ul variants={container} initial="hidden" animate="show">
{items.map(i => (
<motion.li key={i} variants={item}>{i}</motion.li>
))}
</motion.ul>
AnimatePresence (退出动画)
import { AnimatePresence, motion } from "framer-motion";
<AnimatePresence mode="wait">
{isVisible && (
<motion.div
key="modal"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
模态框内容
</motion.div>
)}
</AnimatePresence>
滚动触发
<motion.div
initial={{ opacity: 0, y: 50 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-100px" }}
transition={{ duration: 0.5 }}
>
滚动到视图中时触发动画
</motion.div>
拖拽
<motion.div
drag
dragConstraints={{ left: -100, right: 100, top: -100, bottom: 100 }}
dragElastic={0.1}
>
拖拽我
</motion.div>
布局动画
<motion.div layout layoutId="shared-element">
布局变化时动画的内容
</motion.div>
过渡类型
// 补间 (默认)
transition={{ duration: 0.3, ease: "easeOut" }}
// 弹簧
transition={{ type: "spring", stiffness: 300, damping: 20 }}
// 弹簧预设
transition={{ type: "spring", bounce: 0.25 }}
// 惯性 (用于拖拽)
transition={{ type: "inertia", velocity: 50 }}
缓动函数
// 内置缓动
ease: "linear"
ease: "easeIn"
ease: "easeOut"
ease: "easeInOut"
ease: "circIn"
ease: "circOut"
ease: "circInOut"
ease: "backIn"
ease: "backOut"
ease: "backInOut"
// 自定义三次贝塞尔曲线
ease: [0.17, 0.67, 0.83, 0.67]
减少动画
始终尊重用户偏好:
import { motion, useReducedMotion } from "framer-motion";
function Component() {
const prefersReducedMotion = useReducedMotion();
return (
<motion.div
initial={{ opacity: 0, y: prefersReducedMotion ? 0 : 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: prefersReducedMotion ? 0 : 0.3 }}
>
尊重动画偏好
</motion.div>
);
}
// 或使用媒体查询
const variants = {
initial: { opacity: 0 },
animate: { opacity: 1 },
};
<motion.div
variants={variants}
initial="initial"
animate="animate"
className="motion-reduce:transition-none"
>
常见模式
淡入上移
const fadeInUp = {
initial: { opacity: 0, y: 20 },
animate: { opacity: 1, y: 0 },
transition: { duration: 0.4 }
};
<motion.div {...fadeInUp}>内容</motion.div>
交错列表
const container = {
hidden: { opacity: 0 },
show: {
opacity: 1,
transition: { staggerChildren: 0.1, delayChildren: 0.2 }
}
};
const item = {
hidden: { opacity: 0, x: -20 },
show: { opacity: 1, x: 0 }
};
模态框
<AnimatePresence>
{isOpen && (
<>
{/* 背景遮罩 */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 bg-black/50"
onClick={onClose}
/>
{/* 模态框 */}
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
className="fixed inset-x-4 top-1/2 -translate-y-1/2 ..."
>
模态框内容
</motion.div>
</>
)}
</AnimatePresence>
手风琴
<motion.div
initial={false}
animate={{ height: isOpen ? "auto" : 0 }}
transition={{ duration: 0.3, ease: "easeInOut" }}
className="overflow-hidden"
>
<div className="p-4">手风琴内容</div>
</motion.div>
最佳实践
- 使用变体:代码更清晰,更容易编排
- 尊重减少动画:始终检查
useReducedMotion
- 谨慎使用
layout:可能开销较大,仅在需要时使用
- 退出动画:用
AnimatePresence 包裹
- 交互使用弹簧:悬停/点击感觉更自然
- 页面过渡使用补间:时间更可预测
- GPU加速属性:优先使用
opacity、scale、x、y 而非 width、height