文档

文档

React

概览

React 动画

React Motion 库提供了多种方式来为你的 UI 添加动画效果。从极其简单的基于属性的动画,到更复杂的编排,均可实现。

基本动画

你几乎所有的动画都将在一个<motion />组件上执行。这基本上是一个具有 motion 超能力的 DOM 元素。

import { motion } from "motion/react"

对于基本动画,你可以在animate属性上更新值prop:

<motion.div animate={{ opacity: 1 }} />

。当其 animate 属性中的任何值发生更改时,组件将自动动画到新目标。

可动画化的值

Motion 可以动画化任何 CSS 值,甚至包括浏览器无法动画化的值,例如 mask-image。它支持

  • 数字:0100 等。

  • 包含数字的字符串:"0vh""10px" 等。

  • 颜色:Hex、RGBA、HSLA。

  • 包含多个数字和/或颜色的复杂字符串(如 box-shadow)。

  • display: "none"/"block"visibility: "hidden"/"visible"

值类型转换

通常,值只能在两种相同类型之间进行动画处理(即 "0px""100px")。

颜色可以在 hex、RGBA 和 HSLA 类型之间自由动画。

此外,xywidthheighttopleftrightbottom 可以在不同的值类型之间进行动画处理。

<motion.div
  initial={{ x: "100%" }}
  animate={{ x: "calc(100vw - 50%)" }}
/>

也可以将 widthheight 动画到/出 "auto"

<motion.div
  initial={{ height: 0 }}
  animate={{ height: "auto" }}
/>

注意:如果还要将 display 动画到/出 "none",请用 visibility "hidden" 替换它,因为具有 display: none 的元素无法被测量。

变换

与 CSS 不同,Motion 可以独立地动画化每个变换轴

  • 平移:xyz

  • 缩放:scalescaleXscaleY

  • 旋转:rotaterotateXrotateYrotateZ

  • 倾斜:skewskewXskewY

  • 透视:transformPerspective

motion 组件具有增强的 style 属性,允许你设置单独的变换

<motion.section style={{ x: -20 }} />

独立地动画化变换提供了极大的灵活性,尤其是在手势方面。

<motion.button whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }} />

独立的变换性能出色,但 Motion 的混合引擎也通过直接设置 transform 独特地提供了硬件加速。

<motion.li
  initial={{ transform: "translateX(-100px)" }}
  animate={{ transform: "translateX(0px)" }}
  transition={{ type: "spring" }}
/>

SVG 注意:对于 SVG 组件,可以使用 attrXattrY 设置 xy 属性

变换原点

transform-origin 具有三个可以单独设置和动画化的快捷值

  • originX

  • originY

  • originZ

如果设置为数字,originXY 默认为 01 之间的进度值。originZ 默认为像素。

<motion.div style={{ originX: 0.5 }} />

CSS 变量

React Motion 库可以动画化 CSS 变量的值,也可以使用 CSS 变量作为动画目标。

动画化 CSS 变量

有时,为了动画化多个子元素,能够动画化 CSS 变量会很方便

<motion.ul
  initial={{ '--rotate': '0deg' }}
  animate={{ '--rotate': '360deg' }}
  transition={{ duration: 2, repeat: Infinity }}
>
  <li style={{ transform: 'rotate(var(--rotate))' }} />
  <li style={{ transform: 'rotate(var(--rotate))' }} />
  <li style={{ transform: 'rotate(var(--rotate))' }} />
</motion.ul>

注意:动画化 CSS 变量的值始终会触发重绘,因此使用 MotionValues来设置这种动画可能更高效。

CSS 变量作为动画目标

HTML motion 组件接受带有 CSS 变量的动画目标

<motion.li animate={{ backgroundColor: "var(--action-bg)" }} />

SVG 线条绘制

可以使用三个特殊的属性创建线条绘制动画:pathLengthpathSpacingpathOffset,它们可以用于许多不同的 SVG 元素。

<motion.path initial={{ pathLength: 0 }} animate={{ pathLength: 1 }} />

这三个属性都设置为 01 之间的进度值,1 代表路径的总长度。

路径动画与 circleellipselinepathpolygonpolylinerect 元素兼容。

过渡

默认情况下,Motion 将基于正在动画化的值的类型创建适当的过渡,以实现快速动画。

例如,像 xscale 这样的物理属性使用弹簧物理动画,而像 opacitycolor 这样的值则使用基于持续时间的缓动曲线进行动画处理。

但是,你可以通过animatetransitionprop.

<motion.div
  animate={{ x: 100 }}
  transition={{ ease: "easeOut", duration: 2 }}
/>

定义自己的动画

进入动画animate当首次创建 motion 组件时,如果 animate 中的值与最初渲染的值不同(你可以通过 CSS 或通过initial

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

属性执行初始渲染),它将自动动画到 animate 中的值。你也可以通过设置 initial={false} 完全禁用进入动画。这将使元素以 animate 中定义的值进行渲染。

<motion.div initial={false} animate={{ y: 100 }} />

退出动画

你也可以轻松地在元素退出 DOM 时为其添加动画。

在 React 中,当组件被移除时,通常会立即移除。Motion 提供了animateAnimatePresence组件上执行,它可以在元素执行 exit 动画时将其保留在 DOM 中。

<AnimatePresence>
  {isVisible && (
    <motion.div
      key="modal"
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
    />
  )}
</AnimatePresence>

关键帧

animate 中的值可以设置为一系列关键帧。这将按顺序动画化每个值。

<motion.div animate={{ x: [0, 100, 0] }} />

我们可以通过将值的当前状态设置为 null 来将其用作初始关键帧。

<motion.div animate={{ x: [null, 100, 0] }} />

这样,如果关键帧动画中断了另一个动画,则过渡会感觉更自然。

默认情况下,每个关键帧在整个动画中自然间隔。你可以通过 transition 设置animatetimes选项来覆盖此默认行为。

times 是一个介于 01 之间的进度值数组,用于定义每个关键帧在动画中的位置。

<motion.circle
  cx={500}
  animate={{
    cx: [null, 100, 200],
    transition: { duration: 3, times: [0, 0.2, 1] }
  }}
/>

手势动画

React Motion 库具有快捷属性,用于在手势开始/结束时动画化到/从目标。

<motion.button
  initial={{ opacity: 0 }}
  whileHover={{ backgroundColor: "rgba(220, 220, 220, 1)" }}
  whileTap={{ backgroundColor: "rgba(255, 255, 255, 1)" }}
  whileInView={{ opacity: 1 }}
/>

它支持 hovertapdragfocusinView

变体

animate 设置为目标对于简单的单元素动画很有用。但有时我们希望编排在整个 DOM 中传播的动画。我们可以使用变体来实现。

变体是一组命名的目标。

const variants = {
  visible: { opacity: 1 },
  hidden: { opacity: 0 },
}

它们通过 variants 属性传递给 motion 组件

<motion.div variants={variants} />

现在可以在任何可以定义动画目标的地方通过标签引用这些变体

<motion.div
  variants={variants}
  initial="hidden"
  whileInView="visible"
/>

你也可以通过数组定义多个变体

animate={["visible", "danger"]}

我喜欢将变体与 React 状态一起使用 – 只需将你的状态传递给 animate,现在你就有了一个整洁的地方来定义所有动画目标!

const [status, setStatus] = useState<"inactive" | "active" | "complete">(
  "inactive"
);

<motion.div
  animate={status} // pass in our React state!
  variants={{
    inactive: { scale: 0.9 color: "var(--gray-500)" },
    active: { scale: 1 color: "var(--blue-500)" },
    complete: { scale: 1 color: "var(--blue-500)" }
  }}
>
  <motion.svg
    path={checkmarkPath}
    variants={{
      inactive: { pathLength: 0 },
      active: { pathLength: 0 },
      complete: { pathLength: 1}
    }}
  />
</motion.div>

~ Sam Selikoff,React Motion 库食谱

传播

这对于重用和组合动画目标已经很有用。但它在编排整个树的动画时变得更加强大。

变体将向下流动通过 motion 组件。因此,在此示例中,当 ul 进入视口时,其所有具有“visible”变体的子元素也将动画进入

const list = {
  visible: { opacity: 1 },
  hidden: { opacity: 0 },
}

const item = {
  visible: { opacity: 1, x: 0 },
  hidden: { opacity: 0, x: -100 },
}

return (
  <motion.ul
    initial="hidden"
    whileInView="visible"
    variants={list}
  >
    <motion.li variants={item} />
    <motion.li variants={item} />
    <motion.li variants={item} />
  </motion.ul>
)

编排

默认情况下,此子动画将与父动画同时开始。但是通过变体,我们可以访问新的 transition 属性,例如 when, delayChildren, staggerChildrenstaggerDirection.

const list = {
  visible: {
    opacity: 1,
    transition: {
      when: "beforeChildren",
      staggerChildren: 0.3, // Stagger children by .3 seconds
    },
  },
  hidden: {
    opacity: 0,
    transition: {
      when: "afterChildren",
    },
  },
}

动态变体

每个变体都可以定义为一个函数,该函数在变体变为活动状态时解析。

const variants = {
  hidden: { opacity: 0 },
  visible: (index) => ({
    opacity: 1,
    transition: { delay: index * 0.3 }
  })
}

这些函数被提供了一个参数,该参数通过 custom 属性传递

items.map((item, index) => <motion.div custom={index} variants={variants} />)

这样,每个动画元素的变体都可以以不同的方式解析。

动画控制

声明式动画是大多数 UI 交互的理想选择。但有时我们需要手动控制动画播放。

useAnimatehook可以用于

  • 动画化任何 HTML/SVG 元素(不仅仅是 motion 组件)。

  • 复杂的动画序列。

  • 使用 timespeedplay()pause() 和其他播放控件控制动画。

function MyComponent() {
  const [scope, animate] = useAnimate()

  useEffect(() => {
    const controls = animate([
      [scope.current, { x: "100%" }],
      ["li", { opacity: 1 }]
    ])

    controls.speed = 0.8

    return () => controls.stop()
  }, [])

  return (
    <ul ref={scope}>
      <li />
      <li />
      <li />
    </ul>
  )
}

动画内容

通过传递一个MotionValue 作为 motion 组件的子元素,它将在 HTML 中渲染其最新值。

import { useMotionValue, motion, animate } from "motion/react"

function Counter() {
  const count = useMotionValue(0)

  useEffect(() => {
    const controls = animate(count, 100, { duration: 5 })
    return () => controls.stop()
  }, [])

  return <motion.pre>{count}</motion.pre>
}

这比设置 React 状态更高效,因为 motion 组件将直接设置 innerHTML

React Motion 库提供了多种方式来为你的 UI 添加动画效果。从极其简单的基于属性的动画,到更复杂的编排,均可实现。

基本动画

你几乎所有的动画都将在一个<motion />组件上执行。这基本上是一个具有 motion 超能力的 DOM 元素。

import { motion } from "motion/react"

对于基本动画,你可以在animate属性上更新值prop:

<motion.div animate={{ opacity: 1 }} />

。当其 animate 属性中的任何值发生更改时,组件将自动动画到新目标。

可动画化的值

Motion 可以动画化任何 CSS 值,甚至包括浏览器无法动画化的值,例如 mask-image。它支持

  • 数字:0100 等。

  • 包含数字的字符串:"0vh""10px" 等。

  • 颜色:Hex、RGBA、HSLA。

  • 包含多个数字和/或颜色的复杂字符串(如 box-shadow)。

  • display: "none"/"block"visibility: "hidden"/"visible"

值类型转换

通常,值只能在两种相同类型之间进行动画处理(即 "0px""100px")。

颜色可以在 hex、RGBA 和 HSLA 类型之间自由动画。

此外,xywidthheighttopleftrightbottom 可以在不同的值类型之间进行动画处理。

<motion.div
  initial={{ x: "100%" }}
  animate={{ x: "calc(100vw - 50%)" }}
/>

也可以将 widthheight 动画到/出 "auto"

<motion.div
  initial={{ height: 0 }}
  animate={{ height: "auto" }}
/>

注意:如果还要将 display 动画到/出 "none",请用 visibility "hidden" 替换它,因为具有 display: none 的元素无法被测量。

变换

与 CSS 不同,Motion 可以独立地动画化每个变换轴

  • 平移:xyz

  • 缩放:scalescaleXscaleY

  • 旋转:rotaterotateXrotateYrotateZ

  • 倾斜:skewskewXskewY

  • 透视:transformPerspective

motion 组件具有增强的 style 属性,允许你设置单独的变换

<motion.section style={{ x: -20 }} />

独立地动画化变换提供了极大的灵活性,尤其是在手势方面。

<motion.button whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }} />

独立的变换性能出色,但 Motion 的混合引擎也通过直接设置 transform 独特地提供了硬件加速。

<motion.li
  initial={{ transform: "translateX(-100px)" }}
  animate={{ transform: "translateX(0px)" }}
  transition={{ type: "spring" }}
/>

SVG 注意:对于 SVG 组件,可以使用 attrXattrY 设置 xy 属性

变换原点

transform-origin 具有三个可以单独设置和动画化的快捷值

  • originX

  • originY

  • originZ

如果设置为数字,originXY 默认为 01 之间的进度值。originZ 默认为像素。

<motion.div style={{ originX: 0.5 }} />

CSS 变量

React Motion 库可以动画化 CSS 变量的值,也可以使用 CSS 变量作为动画目标。

动画化 CSS 变量

有时,为了动画化多个子元素,能够动画化 CSS 变量会很方便

<motion.ul
  initial={{ '--rotate': '0deg' }}
  animate={{ '--rotate': '360deg' }}
  transition={{ duration: 2, repeat: Infinity }}
>
  <li style={{ transform: 'rotate(var(--rotate))' }} />
  <li style={{ transform: 'rotate(var(--rotate))' }} />
  <li style={{ transform: 'rotate(var(--rotate))' }} />
</motion.ul>

注意:动画化 CSS 变量的值始终会触发重绘,因此使用 MotionValues来设置这种动画可能更高效。

CSS 变量作为动画目标

HTML motion 组件接受带有 CSS 变量的动画目标

<motion.li animate={{ backgroundColor: "var(--action-bg)" }} />

SVG 线条绘制

可以使用三个特殊的属性创建线条绘制动画:pathLengthpathSpacingpathOffset,它们可以用于许多不同的 SVG 元素。

<motion.path initial={{ pathLength: 0 }} animate={{ pathLength: 1 }} />

这三个属性都设置为 01 之间的进度值,1 代表路径的总长度。

路径动画与 circleellipselinepathpolygonpolylinerect 元素兼容。

过渡

默认情况下,Motion 将基于正在动画化的值的类型创建适当的过渡,以实现快速动画。

例如,像 xscale 这样的物理属性使用弹簧物理动画,而像 opacitycolor 这样的值则使用基于持续时间的缓动曲线进行动画处理。

但是,你可以通过animatetransitionprop.

<motion.div
  animate={{ x: 100 }}
  transition={{ ease: "easeOut", duration: 2 }}
/>

定义自己的动画

进入动画animate当首次创建 motion 组件时,如果 animate 中的值与最初渲染的值不同(你可以通过 CSS 或通过initial

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

属性执行初始渲染),它将自动动画到 animate 中的值。你也可以通过设置 initial={false} 完全禁用进入动画。这将使元素以 animate 中定义的值进行渲染。

<motion.div initial={false} animate={{ y: 100 }} />

退出动画

你也可以轻松地在元素退出 DOM 时为其添加动画。

在 React 中,当组件被移除时,通常会立即移除。Motion 提供了animateAnimatePresence组件上执行,它可以在元素执行 exit 动画时将其保留在 DOM 中。

<AnimatePresence>
  {isVisible && (
    <motion.div
      key="modal"
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
    />
  )}
</AnimatePresence>

关键帧

animate 中的值可以设置为一系列关键帧。这将按顺序动画化每个值。

<motion.div animate={{ x: [0, 100, 0] }} />

我们可以通过将值的当前状态设置为 null 来将其用作初始关键帧。

<motion.div animate={{ x: [null, 100, 0] }} />

这样,如果关键帧动画中断了另一个动画,则过渡会感觉更自然。

默认情况下,每个关键帧在整个动画中自然间隔。你可以通过 transition 设置animatetimes选项来覆盖此默认行为。

times 是一个介于 01 之间的进度值数组,用于定义每个关键帧在动画中的位置。

<motion.circle
  cx={500}
  animate={{
    cx: [null, 100, 200],
    transition: { duration: 3, times: [0, 0.2, 1] }
  }}
/>

手势动画

React Motion 库具有快捷属性,用于在手势开始/结束时动画化到/从目标。

<motion.button
  initial={{ opacity: 0 }}
  whileHover={{ backgroundColor: "rgba(220, 220, 220, 1)" }}
  whileTap={{ backgroundColor: "rgba(255, 255, 255, 1)" }}
  whileInView={{ opacity: 1 }}
/>

它支持 hovertapdragfocusinView

变体

animate 设置为目标对于简单的单元素动画很有用。但有时我们希望编排在整个 DOM 中传播的动画。我们可以使用变体来实现。

变体是一组命名的目标。

const variants = {
  visible: { opacity: 1 },
  hidden: { opacity: 0 },
}

它们通过 variants 属性传递给 motion 组件

<motion.div variants={variants} />

现在可以在任何可以定义动画目标的地方通过标签引用这些变体

<motion.div
  variants={variants}
  initial="hidden"
  whileInView="visible"
/>

你也可以通过数组定义多个变体

animate={["visible", "danger"]}

我喜欢将变体与 React 状态一起使用 – 只需将你的状态传递给 animate,现在你就有了一个整洁的地方来定义所有动画目标!

const [status, setStatus] = useState<"inactive" | "active" | "complete">(
  "inactive"
);

<motion.div
  animate={status} // pass in our React state!
  variants={{
    inactive: { scale: 0.9 color: "var(--gray-500)" },
    active: { scale: 1 color: "var(--blue-500)" },
    complete: { scale: 1 color: "var(--blue-500)" }
  }}
>
  <motion.svg
    path={checkmarkPath}
    variants={{
      inactive: { pathLength: 0 },
      active: { pathLength: 0 },
      complete: { pathLength: 1}
    }}
  />
</motion.div>

~ Sam Selikoff,React Motion 库食谱

传播

这对于重用和组合动画目标已经很有用。但它在编排整个树的动画时变得更加强大。

变体将向下流动通过 motion 组件。因此,在此示例中,当 ul 进入视口时,其所有具有“visible”变体的子元素也将动画进入

const list = {
  visible: { opacity: 1 },
  hidden: { opacity: 0 },
}

const item = {
  visible: { opacity: 1, x: 0 },
  hidden: { opacity: 0, x: -100 },
}

return (
  <motion.ul
    initial="hidden"
    whileInView="visible"
    variants={list}
  >
    <motion.li variants={item} />
    <motion.li variants={item} />
    <motion.li variants={item} />
  </motion.ul>
)

编排

默认情况下,此子动画将与父动画同时开始。但是通过变体,我们可以访问新的 transition 属性,例如 when, delayChildren, staggerChildrenstaggerDirection.

const list = {
  visible: {
    opacity: 1,
    transition: {
      when: "beforeChildren",
      staggerChildren: 0.3, // Stagger children by .3 seconds
    },
  },
  hidden: {
    opacity: 0,
    transition: {
      when: "afterChildren",
    },
  },
}

动态变体

每个变体都可以定义为一个函数,该函数在变体变为活动状态时解析。

const variants = {
  hidden: { opacity: 0 },
  visible: (index) => ({
    opacity: 1,
    transition: { delay: index * 0.3 }
  })
}

这些函数被提供了一个参数,该参数通过 custom 属性传递

items.map((item, index) => <motion.div custom={index} variants={variants} />)

这样,每个动画元素的变体都可以以不同的方式解析。

动画控制

声明式动画是大多数 UI 交互的理想选择。但有时我们需要手动控制动画播放。

useAnimatehook可以用于

  • 动画化任何 HTML/SVG 元素(不仅仅是 motion 组件)。

  • 复杂的动画序列。

  • 使用 timespeedplay()pause() 和其他播放控件控制动画。

function MyComponent() {
  const [scope, animate] = useAnimate()

  useEffect(() => {
    const controls = animate([
      [scope.current, { x: "100%" }],
      ["li", { opacity: 1 }]
    ])

    controls.speed = 0.8

    return () => controls.stop()
  }, [])

  return (
    <ul ref={scope}>
      <li />
      <li />
      <li />
    </ul>
  )
}

动画内容

通过传递一个MotionValue 作为 motion 组件的子元素,它将在 HTML 中渲染其最新值。

import { useMotionValue, motion, animate } from "motion/react"

function Counter() {
  const count = useMotionValue(0)

  useEffect(() => {
    const controls = animate(count, 100, { duration: 5 })
    return () => controls.stop()
  }, [])

  return <motion.pre>{count}</motion.pre>
}

这比设置 React 状态更高效,因为 motion 组件将直接设置 innerHTML

React Motion 库提供了多种方式来为你的 UI 添加动画效果。从极其简单的基于属性的动画,到更复杂的编排,均可实现。

基本动画

你几乎所有的动画都将在一个<motion />组件上执行。这基本上是一个具有 motion 超能力的 DOM 元素。

import { motion } from "motion/react"

对于基本动画,你可以在animate属性上更新值prop:

<motion.div animate={{ opacity: 1 }} />

。当其 animate 属性中的任何值发生更改时,组件将自动动画到新目标。

可动画化的值

Motion 可以动画化任何 CSS 值,甚至包括浏览器无法动画化的值,例如 mask-image。它支持

  • 数字:0100 等。

  • 包含数字的字符串:"0vh""10px" 等。

  • 颜色:Hex、RGBA、HSLA。

  • 包含多个数字和/或颜色的复杂字符串(如 box-shadow)。

  • display: "none"/"block"visibility: "hidden"/"visible"

值类型转换

通常,值只能在两种相同类型之间进行动画处理(即 "0px""100px")。

颜色可以在 hex、RGBA 和 HSLA 类型之间自由动画。

此外,xywidthheighttopleftrightbottom 可以在不同的值类型之间进行动画处理。

<motion.div
  initial={{ x: "100%" }}
  animate={{ x: "calc(100vw - 50%)" }}
/>

也可以将 widthheight 动画到/出 "auto"

<motion.div
  initial={{ height: 0 }}
  animate={{ height: "auto" }}
/>

注意:如果还要将 display 动画到/出 "none",请用 visibility "hidden" 替换它,因为具有 display: none 的元素无法被测量。

变换

与 CSS 不同,Motion 可以独立地动画化每个变换轴

  • 平移:xyz

  • 缩放:scalescaleXscaleY

  • 旋转:rotaterotateXrotateYrotateZ

  • 倾斜:skewskewXskewY

  • 透视:transformPerspective

motion 组件具有增强的 style 属性,允许你设置单独的变换

<motion.section style={{ x: -20 }} />

独立地动画化变换提供了极大的灵活性,尤其是在手势方面。

<motion.button whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }} />

独立的变换性能出色,但 Motion 的混合引擎也通过直接设置 transform 独特地提供了硬件加速。

<motion.li
  initial={{ transform: "translateX(-100px)" }}
  animate={{ transform: "translateX(0px)" }}
  transition={{ type: "spring" }}
/>

SVG 注意:对于 SVG 组件,可以使用 attrXattrY 设置 xy 属性

变换原点

transform-origin 具有三个可以单独设置和动画化的快捷值

  • originX

  • originY

  • originZ

如果设置为数字,originXY 默认为 01 之间的进度值。originZ 默认为像素。

<motion.div style={{ originX: 0.5 }} />

CSS 变量

React Motion 库可以动画化 CSS 变量的值,也可以使用 CSS 变量作为动画目标。

动画化 CSS 变量

有时,为了动画化多个子元素,能够动画化 CSS 变量会很方便

<motion.ul
  initial={{ '--rotate': '0deg' }}
  animate={{ '--rotate': '360deg' }}
  transition={{ duration: 2, repeat: Infinity }}
>
  <li style={{ transform: 'rotate(var(--rotate))' }} />
  <li style={{ transform: 'rotate(var(--rotate))' }} />
  <li style={{ transform: 'rotate(var(--rotate))' }} />
</motion.ul>

注意:动画化 CSS 变量的值始终会触发重绘,因此使用 MotionValues来设置这种动画可能更高效。

CSS 变量作为动画目标

HTML motion 组件接受带有 CSS 变量的动画目标

<motion.li animate={{ backgroundColor: "var(--action-bg)" }} />

SVG 线条绘制

可以使用三个特殊的属性创建线条绘制动画:pathLengthpathSpacingpathOffset,它们可以用于许多不同的 SVG 元素。

<motion.path initial={{ pathLength: 0 }} animate={{ pathLength: 1 }} />

这三个属性都设置为 01 之间的进度值,1 代表路径的总长度。

路径动画与 circleellipselinepathpolygonpolylinerect 元素兼容。

过渡

默认情况下,Motion 将基于正在动画化的值的类型创建适当的过渡,以实现快速动画。

例如,像 xscale 这样的物理属性使用弹簧物理动画,而像 opacitycolor 这样的值则使用基于持续时间的缓动曲线进行动画处理。

但是,你可以通过animatetransitionprop.

<motion.div
  animate={{ x: 100 }}
  transition={{ ease: "easeOut", duration: 2 }}
/>

定义自己的动画

进入动画animate当首次创建 motion 组件时,如果 animate 中的值与最初渲染的值不同(你可以通过 CSS 或通过initial

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

属性执行初始渲染),它将自动动画到 animate 中的值。你也可以通过设置 initial={false} 完全禁用进入动画。这将使元素以 animate 中定义的值进行渲染。

<motion.div initial={false} animate={{ y: 100 }} />

退出动画

你也可以轻松地在元素退出 DOM 时为其添加动画。

在 React 中,当组件被移除时,通常会立即移除。Motion 提供了animateAnimatePresence组件上执行,它可以在元素执行 exit 动画时将其保留在 DOM 中。

<AnimatePresence>
  {isVisible && (
    <motion.div
      key="modal"
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
    />
  )}
</AnimatePresence>

关键帧

animate 中的值可以设置为一系列关键帧。这将按顺序动画化每个值。

<motion.div animate={{ x: [0, 100, 0] }} />

我们可以通过将值的当前状态设置为 null 来将其用作初始关键帧。

<motion.div animate={{ x: [null, 100, 0] }} />

这样,如果关键帧动画中断了另一个动画,则过渡会感觉更自然。

默认情况下,每个关键帧在整个动画中自然间隔。你可以通过 transition 设置animatetimes选项来覆盖此默认行为。

times 是一个介于 01 之间的进度值数组,用于定义每个关键帧在动画中的位置。

<motion.circle
  cx={500}
  animate={{
    cx: [null, 100, 200],
    transition: { duration: 3, times: [0, 0.2, 1] }
  }}
/>

手势动画

React Motion 库具有快捷属性,用于在手势开始/结束时动画化到/从目标。

<motion.button
  initial={{ opacity: 0 }}
  whileHover={{ backgroundColor: "rgba(220, 220, 220, 1)" }}
  whileTap={{ backgroundColor: "rgba(255, 255, 255, 1)" }}
  whileInView={{ opacity: 1 }}
/>

它支持 hovertapdragfocusinView

变体

animate 设置为目标对于简单的单元素动画很有用。但有时我们希望编排在整个 DOM 中传播的动画。我们可以使用变体来实现。

变体是一组命名的目标。

const variants = {
  visible: { opacity: 1 },
  hidden: { opacity: 0 },
}

它们通过 variants 属性传递给 motion 组件

<motion.div variants={variants} />

现在可以在任何可以定义动画目标的地方通过标签引用这些变体

<motion.div
  variants={variants}
  initial="hidden"
  whileInView="visible"
/>

你也可以通过数组定义多个变体

animate={["visible", "danger"]}

我喜欢将变体与 React 状态一起使用 – 只需将你的状态传递给 animate,现在你就有了一个整洁的地方来定义所有动画目标!

const [status, setStatus] = useState<"inactive" | "active" | "complete">(
  "inactive"
);

<motion.div
  animate={status} // pass in our React state!
  variants={{
    inactive: { scale: 0.9 color: "var(--gray-500)" },
    active: { scale: 1 color: "var(--blue-500)" },
    complete: { scale: 1 color: "var(--blue-500)" }
  }}
>
  <motion.svg
    path={checkmarkPath}
    variants={{
      inactive: { pathLength: 0 },
      active: { pathLength: 0 },
      complete: { pathLength: 1}
    }}
  />
</motion.div>

~ Sam Selikoff,React Motion 库食谱

传播

这对于重用和组合动画目标已经很有用。但它在编排整个树的动画时变得更加强大。

变体将向下流动通过 motion 组件。因此,在此示例中,当 ul 进入视口时,其所有具有“visible”变体的子元素也将动画进入

const list = {
  visible: { opacity: 1 },
  hidden: { opacity: 0 },
}

const item = {
  visible: { opacity: 1, x: 0 },
  hidden: { opacity: 0, x: -100 },
}

return (
  <motion.ul
    initial="hidden"
    whileInView="visible"
    variants={list}
  >
    <motion.li variants={item} />
    <motion.li variants={item} />
    <motion.li variants={item} />
  </motion.ul>
)

编排

默认情况下,此子动画将与父动画同时开始。但是通过变体,我们可以访问新的 transition 属性,例如 when, delayChildren, staggerChildrenstaggerDirection.

const list = {
  visible: {
    opacity: 1,
    transition: {
      when: "beforeChildren",
      staggerChildren: 0.3, // Stagger children by .3 seconds
    },
  },
  hidden: {
    opacity: 0,
    transition: {
      when: "afterChildren",
    },
  },
}

动态变体

每个变体都可以定义为一个函数,该函数在变体变为活动状态时解析。

const variants = {
  hidden: { opacity: 0 },
  visible: (index) => ({
    opacity: 1,
    transition: { delay: index * 0.3 }
  })
}

这些函数被提供了一个参数,该参数通过 custom 属性传递

items.map((item, index) => <motion.div custom={index} variants={variants} />)

这样,每个动画元素的变体都可以以不同的方式解析。

动画控制

声明式动画是大多数 UI 交互的理想选择。但有时我们需要手动控制动画播放。

useAnimatehook可以用于

  • 动画化任何 HTML/SVG 元素(不仅仅是 motion 组件)。

  • 复杂的动画序列。

  • 使用 timespeedplay()pause() 和其他播放控件控制动画。

function MyComponent() {
  const [scope, animate] = useAnimate()

  useEffect(() => {
    const controls = animate([
      [scope.current, { x: "100%" }],
      ["li", { opacity: 1 }]
    ])

    controls.speed = 0.8

    return () => controls.stop()
  }, [])

  return (
    <ul ref={scope}>
      <li />
      <li />
      <li />
    </ul>
  )
}

动画内容

通过传递一个MotionValue 作为 motion 组件的子元素,它将在 HTML 中渲染其最新值。

import { useMotionValue, motion, animate } from "motion/react"

function Counter() {
  const count = useMotionValue(0)

  useEffect(() => {
    const controls = animate(count, 100, { duration: 5 })
    return () => controls.stop()
  }, [])

  return <motion.pre>{count}</motion.pre>
}

这比设置 React 状态更高效,因为 motion 组件将直接设置 innerHTML

React 动画

示例

超越基础

Motion+是一次性付费,终身会员资格。

除了高级 Motion 功能、早期访问内容和私人 Discord 社区外,你还将解锁访问 90 多个高级示例源代码的权限,这些示例将此页面上的 API 提升到一个新的水平。

加载中...
加载中...
加载中...
保持关注

订阅以获取最新新闻和更新。

©2025 Motion Division Ltd.
保持关注

订阅以获取最新新闻和更新。

©2025 Motion Division Ltd.