前端开发
在 React/Next.js 中用 Framer…
在 React 或 Next.js 中编写/审查 Framer Motion 动画代码时,处理挂载卸载动画、布局动画、程序化控制与 SSR 兼容。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 React/Next.js 中用 F通用
解决思路
- 安装依赖:运行 `npm install framer-motion`。
- 用 AnimatePresence 包裹条件渲染的动画组件:在 AnimatePresence 内部用 `{isOpen && <motion.div key="modal" initial={{opacity:0}} animate={{opacity:1}} exit={{opacity:0}} />}` 实现挂载/卸载动画。
- 按需选择 AnimatePresence 模式:`"sync"` 所有子元素同时动画(默认)、`"wait"` 等待退出完成再进入、`"popLayout"` 退出元素立即从布局中移除。
- 用 `layout` 属性实现自动位置动画:在容器和列表项上分别加 `<motion.div layout>`,并为每项提供唯一 `key`。
- 用 `layoutId` 实现共享元素过渡:在两个页面/组件中使用相同的 `layoutId="card"`,元素会在位置之间平滑过渡。
- 用 `useAnimation` 做程序化控制:`const controls = useAnimation()`,通过 `await controls.start({ x: 100, transition: { duration: 0.5 } })` 依次执行动画,并把 `animate={controls}` 传给 motion 组件。
- 使用动态动画:在 `animate` 中传入函数,如 `x: (i) => i * 50`、`opacity: (i) => i * 0.1 + 0.5`。
- 处理 SSR(Next.js):创建 `"use client"` 的 ClientOnly 包装组件,用 `useState(false)` + `useEffect(() => setMounted(true), [])`,未挂载时返回 fallback,挂载后再渲染 children。
- 用 LazyMotion 优化包体积:从 framer-motion 引入 `LazyMotion, m`,定义 features 后包裹应用,并用 `m.div` 替代 `motion.div`。
- 遵循最佳实践:条件渲染的动画组件用 AnimatePresence 包裹;共享元素过渡用 layoutId;用 LazyMotion 减小包体积;SSR 场景只在挂载后渲染动画。
适用边界 · 注意事项
- 不要在没有 key 的情况下对条件渲染的子元素使用 AnimatePresence。
- 不要对布局属性(width、height)做动画。
- 不要忽略 SSR 水合问题,也不要在同一组件层级使用重复的 layoutId。