SuperAPI AI 工具集

framer-motion-layout

前端与建站

查看项目

更新于 10-15 16:27

技能介绍

用途

本技能用于在 Framer Motion 中实现布局动画,主要覆盖三类场景:共享元素过渡、布局重排(reordering)动画,以及协同的挂载/卸载动画。当用户询问 Framer Motion 布局动画、layoutId 或 AnimatePresence 时适用。

相关技能:核心动画使用 framer-motion-core;变体使用 framer-motion-variants;React 集成使用 framer-motion-react。

主要能力

layout 属性

layout 属性在布局变化时启用自动位置动画:

<motion.div layout>
  {items.map(item => (
    <motion.div key={item.id} layout />
  ))}
</motion.div>

布局模式

模式 行为
true 同时动画位置与尺寸
"position" 仅动画位置
"size" 仅动画尺寸
<motion.div layout="position" />
<motion.div layout="size" />

用 layoutId 实现共享元素过渡

layoutId 可在不同组件中的元素之间实现平滑过渡。

页面过渡:

// Page A
function CardA() {
  return <motion.div layoutId="card" />;
}

// Page B
function CardB() {
  return <motion.div layoutId="card" />;
}

当 CardA 卸载、CardB 以相同 layoutId 挂载时,Framer Motion 会在两个位置之间平滑动画该元素。

模态浮层:

function ListItem({ item, onClick }) {
  return (
    <motion.div layoutId={`item-${item.id}`} onClick={onClick}>
      {item.name}
    </motion.div>
  );
}

function Modal({ item }) {
  return (
    <motion.div layoutId={`item-${item.id}`}>
      <h2>{item.name}</h2>
      <p>{item.description}</p>
    </motion.div>
  );
}

用于布局的 AnimatePresence

AnimatePresence 可启用退出动画:

import { AnimatePresence, motion } from "framer-motion";

function TodoList({ todos }) {
  return (
    <motion.ul>
      <AnimatePresence>
        {todos.map(todo => (
          <motion.li
            key={todo.id}
            layout
            initial={{ opacity: 0, x: -20 }}
            animate={{ opacity: 1, x: 0 }}
            exit={{ opacity: 0, x: 20 }}
          />
        ))}
      </AnimatePresence>
    </motion.ul>
  );
}

AnimatePresence 模式

<AnimatePresence mode="wait">
  {isOpen && <Modal key="modal" />}
</AnimatePresence>
模式 说明
"sync" 所有动画同时运行(默认)
"wait" 退出完成后才开始进入
"popLayout" 退出的元素立刻从布局中移除

可重排列表

结合 layout 与 drag 可实现可重排列表:

function ReorderableList({ items, setItems }) {
  return (
    <AnimatePresence>
      {items.map(item => (
        <motion.div
          key={item.id}
          layout
          drag
          dragConstraints={{ top: 0, bottom: 0 }}
          onDragEnd={({ info, target }) => {
            // Calculate new index and update
          }}
          initial={{ opacity: 0, scale: 0.8 }}
          animate={{ opacity: 1, scale: 1 }}
          exit={{ opacity: 0, scale: 0.8 }}
        />
      ))}
    </AnimatePresence>
  );
}

网格中的共享布局

function Grid({ items }) {
  return (
    <motion.div
      layout
      style={{
        display: "grid",
        gridTemplateColumns: "repeat(auto-fill, minmax(100px, 1fr))",
        gap: 10
      }}
    >
      {items.map(item => (
        <motion.div
          key={item.id}
          layout
          style={{
            width: "100%",
            aspectRatio: 1,
            backgroundColor: item.color
          }}
        />
      ))}
    </motion.div>
  );
}

退出动画

使用 AnimatePresence 的元素必须定义退出状态:

<motion.div
  initial={{ opacity: 0, scale: 0 }}
  animate={{ opacity: 1, scale: 1 }}
  exit={{ opacity: 0, scale: 0 }}
/>

结合 layout 的退出:

<motion.div
  layout
  exit={{ opacity: 0, x: -100, transition: { duration: 0.3 } }}
/>

用 layoutId 实现交叉淡化(crossfade)

当多个元素在同一层级共享 layoutId 时:

function Toggle() {
  const [showA, setShowA] = useState(true);

  return (
    <AnimatePresence mode="popLayout">
      {showA ? (
        <motion.div
          key="a"
          layoutId="shape"
          style={{ backgroundColor: "red" }}
        />
      ) : (
        <motion.div
          key="b"
          layoutId="shape"
          style={{ backgroundColor: "blue", borderRadius: "50%" }}
        />
      )}
    </AnimatePresence>
  );
}

该元素会在各状态之间平滑变形,包括 border radius。

使用方式(最佳实践)

  • ✅ 使用 layoutId 实现路由/页面之间的共享元素过渡。
  • ✅ 为动画列表包裹 AnimatePresence 以启用退出动画。
  • ✅ 使用 layout 属性实现自动位置动画。
  • ✅ 使用 AnimatePresence mode="popLayout" 实现平滑重排。
  • ✅ 为使用 AnimatePresence 的组件定义退出状态。
  • ✅ 当子元素需要动画位置时,在父容器上使用 layout。

避免事项:

  • ❌ 忘记为条件渲染的动画组件包裹 AnimatePresence。
  • ❌ 在同一层级的多个元素上使用相同的 layoutId。
  • ❌ 忘记为会卸载的组件定义退出状态。
  • ❌ 在子元素缺少正确 key 的情况下使用布局动画。
  • ❌ 同时动画过多布局元素——应分组或错开(stagger)。

适用场景

  • 共享元素过渡(如卡片到详情的展开)。
  • 页面/路由切换过渡。
  • 模态浮层与列表项的联动。
  • 列表重排(配合 drag)。
  • 网格布局变化动画。
  • 条件渲染内容的进入/退出动画。

限制

资料未提供计费、价格、平台限制或效果指标等信息,这些事实暂未提供。

了解更多

  • https://www.framer.com/motion/layout-animations/
  • https://www.framer.com/motion/animate-presence/