React 动画
React Motion 库提供了多种方式来为你的 UI 添加动画效果。从极其简单的基于属性的动画,到更复杂的编排,均可实现。
基本动画
你几乎所有的动画都将在一个<motion />
组件上执行。这基本上是一个具有 motion 超能力的 DOM 元素。
import { motion } from "motion/react"
<motion.div animate={{ opacity: 1 }} />
。当其 animate 属性中的任何值发生更改时,组件将自动动画到新目标。
可动画化的值
Motion 可以动画化任何 CSS 值,甚至包括浏览器无法动画化的值,例如 mask-image
。它支持
数字:
0
、100
等。包含数字的字符串:
"0vh"
、"10px"
等。颜色:Hex、RGBA、HSLA。
包含多个数字和/或颜色的复杂字符串(如
box-shadow
)。display: "none"/"block"
和visibility: "hidden"/"visible"
。
值类型转换
通常,值只能在两种相同类型之间进行动画处理(即 "0px"
到 "100px"
)。
颜色可以在 hex、RGBA 和 HSLA 类型之间自由动画。
此外,x
、y
、width
、height
、top
、left
、right
和 bottom
可以在不同的值类型之间进行动画处理。
<motion.div initial={{ x: "100%" }} animate={{ x: "calc(100vw - 50%)" }} />
也可以将 width
和 height
动画到/出 "auto"
。
<motion.div initial={{ height: 0 }} animate={{ height: "auto" }} />
注意:如果还要将 display
动画到/出 "none"
,请用 visibility
"hidden"
替换它,因为具有 display: none
的元素无法被测量。
变换
与 CSS 不同,Motion 可以独立地动画化每个变换轴
平移:
x
、y
、z
缩放:
scale
、scaleX
、scaleY
旋转:
rotate
、rotateX
、rotateY
、rotateZ
倾斜:
skew
、skewX
、skewY
透视:
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 组件,可以使用 attrX
和 attrY
设置 x
和 y
属性。
变换原点
transform-origin
具有三个可以单独设置和动画化的快捷值
originX
originY
originZ
如果设置为数字,originX
和 Y
默认为 0
和 1
之间的进度值。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 变量的值始终会触发重绘,因此使用 MotionValue
s来设置这种动画可能更高效。
CSS 变量作为动画目标
HTML motion
组件接受带有 CSS 变量的动画目标
<motion.li animate={{ backgroundColor: "var(--action-bg)" }} />
SVG 线条绘制
可以使用三个特殊的属性创建线条绘制动画:pathLength
、pathSpacing
和 pathOffset
,它们可以用于许多不同的 SVG 元素。
<motion.path initial={{ pathLength: 0 }} animate={{ pathLength: 1 }} />
这三个属性都设置为 0
和 1
之间的进度值,1
代表路径的总长度。
路径动画与 circle
、ellipse
、line
、path
、polygon
、polyline
和 rect
元素兼容。
过渡
默认情况下,Motion 将基于正在动画化的值的类型创建适当的过渡,以实现快速动画。
例如,像 x
或 scale
这样的物理属性使用弹簧物理动画,而像 opacity
或 color
这样的值则使用基于持续时间的缓动曲线进行动画处理。
但是,你可以通过animatetransition
prop.
<motion.div animate={{ x: 100 }} transition={{ ease: "easeOut", duration: 2 }} />
定义自己的动画
进入动画animate当首次创建
initial motion
组件时,如果 animate
中的值与最初渲染的值不同(你可以通过 CSS 或通过
<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
是一个介于 0
和 1
之间的进度值数组,用于定义每个关键帧在动画中的位置。
<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 }} />
它支持 hover
、tap
、drag
、focus
和 inView
。
变体
将 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
, staggerChildren
和staggerDirection
.
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 交互的理想选择。但有时我们需要手动控制动画播放。
useAnimate
hook可以用于
动画化任何 HTML/SVG 元素(不仅仅是
motion
组件)。复杂的动画序列。
使用
time
、speed
、play()
、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"
<motion.div animate={{ opacity: 1 }} />
。当其 animate 属性中的任何值发生更改时,组件将自动动画到新目标。
可动画化的值
Motion 可以动画化任何 CSS 值,甚至包括浏览器无法动画化的值,例如 mask-image
。它支持
数字:
0
、100
等。包含数字的字符串:
"0vh"
、"10px"
等。颜色:Hex、RGBA、HSLA。
包含多个数字和/或颜色的复杂字符串(如
box-shadow
)。display: "none"/"block"
和visibility: "hidden"/"visible"
。
值类型转换
通常,值只能在两种相同类型之间进行动画处理(即 "0px"
到 "100px"
)。
颜色可以在 hex、RGBA 和 HSLA 类型之间自由动画。
此外,x
、y
、width
、height
、top
、left
、right
和 bottom
可以在不同的值类型之间进行动画处理。
<motion.div initial={{ x: "100%" }} animate={{ x: "calc(100vw - 50%)" }} />
也可以将 width
和 height
动画到/出 "auto"
。
<motion.div initial={{ height: 0 }} animate={{ height: "auto" }} />
注意:如果还要将 display
动画到/出 "none"
,请用 visibility
"hidden"
替换它,因为具有 display: none
的元素无法被测量。
变换
与 CSS 不同,Motion 可以独立地动画化每个变换轴
平移:
x
、y
、z
缩放:
scale
、scaleX
、scaleY
旋转:
rotate
、rotateX
、rotateY
、rotateZ
倾斜:
skew
、skewX
、skewY
透视:
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 组件,可以使用 attrX
和 attrY
设置 x
和 y
属性。
变换原点
transform-origin
具有三个可以单独设置和动画化的快捷值
originX
originY
originZ
如果设置为数字,originX
和 Y
默认为 0
和 1
之间的进度值。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 变量的值始终会触发重绘,因此使用 MotionValue
s来设置这种动画可能更高效。
CSS 变量作为动画目标
HTML motion
组件接受带有 CSS 变量的动画目标
<motion.li animate={{ backgroundColor: "var(--action-bg)" }} />
SVG 线条绘制
可以使用三个特殊的属性创建线条绘制动画:pathLength
、pathSpacing
和 pathOffset
,它们可以用于许多不同的 SVG 元素。
<motion.path initial={{ pathLength: 0 }} animate={{ pathLength: 1 }} />
这三个属性都设置为 0
和 1
之间的进度值,1
代表路径的总长度。
路径动画与 circle
、ellipse
、line
、path
、polygon
、polyline
和 rect
元素兼容。
过渡
默认情况下,Motion 将基于正在动画化的值的类型创建适当的过渡,以实现快速动画。
例如,像 x
或 scale
这样的物理属性使用弹簧物理动画,而像 opacity
或 color
这样的值则使用基于持续时间的缓动曲线进行动画处理。
但是,你可以通过animatetransition
prop.
<motion.div animate={{ x: 100 }} transition={{ ease: "easeOut", duration: 2 }} />
定义自己的动画
进入动画animate当首次创建
initial motion
组件时,如果 animate
中的值与最初渲染的值不同(你可以通过 CSS 或通过
<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
是一个介于 0
和 1
之间的进度值数组,用于定义每个关键帧在动画中的位置。
<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 }} />
它支持 hover
、tap
、drag
、focus
和 inView
。
变体
将 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
, staggerChildren
和staggerDirection
.
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 交互的理想选择。但有时我们需要手动控制动画播放。
useAnimate
hook可以用于
动画化任何 HTML/SVG 元素(不仅仅是
motion
组件)。复杂的动画序列。
使用
time
、speed
、play()
、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"
<motion.div animate={{ opacity: 1 }} />
。当其 animate 属性中的任何值发生更改时,组件将自动动画到新目标。
可动画化的值
Motion 可以动画化任何 CSS 值,甚至包括浏览器无法动画化的值,例如 mask-image
。它支持
数字:
0
、100
等。包含数字的字符串:
"0vh"
、"10px"
等。颜色:Hex、RGBA、HSLA。
包含多个数字和/或颜色的复杂字符串(如
box-shadow
)。display: "none"/"block"
和visibility: "hidden"/"visible"
。
值类型转换
通常,值只能在两种相同类型之间进行动画处理(即 "0px"
到 "100px"
)。
颜色可以在 hex、RGBA 和 HSLA 类型之间自由动画。
此外,x
、y
、width
、height
、top
、left
、right
和 bottom
可以在不同的值类型之间进行动画处理。
<motion.div initial={{ x: "100%" }} animate={{ x: "calc(100vw - 50%)" }} />
也可以将 width
和 height
动画到/出 "auto"
。
<motion.div initial={{ height: 0 }} animate={{ height: "auto" }} />
注意:如果还要将 display
动画到/出 "none"
,请用 visibility
"hidden"
替换它,因为具有 display: none
的元素无法被测量。
变换
与 CSS 不同,Motion 可以独立地动画化每个变换轴
平移:
x
、y
、z
缩放:
scale
、scaleX
、scaleY
旋转:
rotate
、rotateX
、rotateY
、rotateZ
倾斜:
skew
、skewX
、skewY
透视:
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 组件,可以使用 attrX
和 attrY
设置 x
和 y
属性。
变换原点
transform-origin
具有三个可以单独设置和动画化的快捷值
originX
originY
originZ
如果设置为数字,originX
和 Y
默认为 0
和 1
之间的进度值。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 变量的值始终会触发重绘,因此使用 MotionValue
s来设置这种动画可能更高效。
CSS 变量作为动画目标
HTML motion
组件接受带有 CSS 变量的动画目标
<motion.li animate={{ backgroundColor: "var(--action-bg)" }} />
SVG 线条绘制
可以使用三个特殊的属性创建线条绘制动画:pathLength
、pathSpacing
和 pathOffset
,它们可以用于许多不同的 SVG 元素。
<motion.path initial={{ pathLength: 0 }} animate={{ pathLength: 1 }} />
这三个属性都设置为 0
和 1
之间的进度值,1
代表路径的总长度。
路径动画与 circle
、ellipse
、line
、path
、polygon
、polyline
和 rect
元素兼容。
过渡
默认情况下,Motion 将基于正在动画化的值的类型创建适当的过渡,以实现快速动画。
例如,像 x
或 scale
这样的物理属性使用弹簧物理动画,而像 opacity
或 color
这样的值则使用基于持续时间的缓动曲线进行动画处理。
但是,你可以通过animatetransition
prop.
<motion.div animate={{ x: 100 }} transition={{ ease: "easeOut", duration: 2 }} />
定义自己的动画
进入动画animate当首次创建
initial motion
组件时,如果 animate
中的值与最初渲染的值不同(你可以通过 CSS 或通过
<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
是一个介于 0
和 1
之间的进度值数组,用于定义每个关键帧在动画中的位置。
<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 }} />
它支持 hover
、tap
、drag
、focus
和 inView
。
变体
将 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
, staggerChildren
和staggerDirection
.
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 交互的理想选择。但有时我们需要手动控制动画播放。
useAnimate
hook可以用于
动画化任何 HTML/SVG 元素(不仅仅是
motion
组件)。复杂的动画序列。
使用
time
、speed
、play()
、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
。