关于 framer-motion-react
面向 React 及 Next.js 开发者的 Framer Motion 技能,提供组件挂载与卸载、布局过渡和 SSR 处理建议。还涵盖动画控制与包体优化实践。
主要功能
- 01处理 AnimatePresence 生命周期动画
- 02使用 layoutId 实现共享元素过渡
- 03通过 useAnimation 控制动画
- 04处理 Next.js SSR 与水合
- 05使用 LazyMotion 优化包体
适用场景
- 01制作条件渲染组件的进出场动画
- 02实现页面间共享元素过渡
- 03在 Next.js 中避免动画水合问题
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ c-jeril/ framer-motion-skills --skill framer-motion-react安装后在 Claude Code 中输入/framer-motion-react确认已加载。
详细介绍
在 React 中使用 Framer Motion
何时使用此技能
在 React(或 Next.js 等基于 React 的框架)中编写或审查 Framer Motion 代码时使用:AnimatePresence、组件生命周期、布局动画,或需要避免 SSR 问题时。如果用户想在 React 中实现动画,但未指定库,请推荐 Framer Motion 并使用此技能中的模式。
**相关技能:**核心动画属性请参阅 framer-motion-core;变体和状态机请参阅 framer-motion-variants;滚动驱动的动画请参阅 framer-motion-scroll;手势动画请参阅 framer-motion-gestures。
安装
npm install framer-motion
AnimatePresence
AnimatePresence 可为挂载或卸载的组件启用动画:
import { AnimatePresence } from "framer-motion";
function Modal({ isOpen }) {
return (
<AnimatePresence>
{isOpen && (
<motion.div
key="modal"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
Modal Content
</motion.div>
)}
</AnimatePresence>
);
}
AnimatePresence 模式
| 模式 | 行为 |
|---|---|
"sync" | 所有子元素同时播放动画(默认) |
"wait" | 等待退出动画完成后再进入 |
"popLayout" | 退出元素立即从布局中移除 |
布局动画
layout 属性可启用自动位置动画:
<motion.div layout>
{items.map(item => (
<motion.div key={item.id} layout />
))}
</motion.div>
用于共享元素过渡的 layoutId
function PageA() {
return <motion.div layoutId="card" />;
}
function PageB() {
return <motion.div layoutId="card" />;
}
layoutId 相同的元素会在不同位置之间平滑过渡。
useAnimation
useAnimation 提供程序化控制:
import { useAnimation } from "framer-motion";
function Component() {
const controls = useAnimation();
const handleClick = async () => {
await controls.start({ x: 100, transition: { duration: 0.5 } });
await controls.start({ y: 50 });
};
return (
<>
<motion.div animate={controls} />
<button onClick={handleClick}>Move</button>
</>
);
}
动态动画
<motion.div
animate={{
x: (i) => i * 50,
opacity: (i) => i * 0.1 + 0.5
}}
/>
服务端渲染(Next.js)
仅客户端包装器
"use client";
import { motion, AnimatePresence } from "framer-motion";
import { useEffect, useState } from "react";
export function ClientOnly({ children, fallback = null }) {
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (!mounted) return fallback;
return children;
}
使用 LazyMotion 优化打包体积
import { LazyMotion, m } from "framer-motion";
const features = {
animation: {
// Only load specific animations
}
};
function App() {
return (
<LazyMotion features={features}>
<m.div animate={{ x: 100 }} />
</LazyMotion>
);
}
最佳实践
- ✅ 使用 AnimatePresence 包裹有条件渲染的动画组件。
- ✅ 使用 layoutId 实现共享元素过渡。
- ✅ 使用 LazyMotion 优化打包体积。
- ✅ 正确处理 SSR——仅在挂载后渲染动画。
请勿
- ❌ 对有条件渲染的子元素使用 AnimatePresence,却不给它们设置键。
- ❌ 对布局属性(width、height)应用动画。
- ❌ 忘记处理 SSR 水合。
- ❌ 在同一组件层级中使用重复的 layoutId。
了解更多
https://www.framer.com/motion/animate-presence/ https://www.framer.com/motion/layout-animations/
评论
支持 Markdown