mcpField
F
framer-motion-react

framer-motion-react

github.com/c-jeril设计与 UI10835 次安装30 周前更新
代码仓库

关于 framer-motion-react

面向 React 及 Next.js 开发者的 Framer Motion 技能,提供组件挂载与卸载、布局过渡和 SSR 处理建议。还涵盖动画控制与包体优化实践。

主要功能

  1. 01处理 AnimatePresence 生命周期动画
  2. 02使用 layoutId 实现共享元素过渡
  3. 03通过 useAnimation 控制动画
  4. 04处理 Next.js SSR 与水合
  5. 05使用 LazyMotion 优化包体

适用场景

  1. 01制作条件渲染组件的进出场动画
  2. 02实现页面间共享元素过渡
  3. 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