Framer Motion - 为 React 提供精美的动画和交互。🤤
Framer Motion 是什么?🤔
我们会做什么?😏
之前,我介绍了 React Spring,一个基于弹簧物理的动画库。我们制作了一些简单的切换动画,以及一个略微复杂的悬停动画/过渡。
嗯,一切都很棒,很酷,直到我想到 Framer Motion!这是一个非常棒的库,它能让你的原型栩栩如生,而且比 React Spring 的易用性高出一倍。
让我们看看它提供的功能以及为什么你应该在下一个 React 项目中使用它。
Framer Motion 是什么?🤔
Framer Motion是一个适用于 React 的生产级动效库。它充分利用了Framer原型设计工具的强大功能,并且完全开源。
有一些开箱即用的功能或卖点:
- 动画(CodeSandbox 演示)
- 变体。 (CodeSandbox 演示)
- 手势。 (CodeSandbox 演示)
- 拖动。(CodeSandbox 演示)
- 滚动。(CodeSandbox 演示)
- 路径。(CodeSandbox 演示)
我最喜欢的是变体,点击下面进行互动:
还,
- 它使用服务器端渲染。
- 它支持 CSS 变量。
- 您可以轻松卸载动画。
- 它具有出色的可访问性选项。
- 您可以将设计从 Framer 转移到 Framer Motion。
在执行任何操作之前,我们需要了解一些基础知识,很可能是它的 API。
运动 API
这就是 Framer Motion 的核心所在。它为我们提供了各种各样的选项,包括你在上文中看到的那些。
➡motion
组件。
它是库中内置的 React 组件,几乎适用于您在 UI 中使用的所有 HTML 或 SVG 元素。这些 DOM 元素已针对 60fps 动画和手势支持进行了优化。
好处是,我们可以轻松地将静态 HTML/SVG 元素转换为动态组件。例如,如果我们有一个常用的div
,那么只需motion.
在该 HTML 标签前面添加 ,就得到了一个motion
组件!这样<div>
就变成了<motion.div>
。
它允许您:
- 以声明方式或命令方式为组件设置动画。
- 通过变体在整个 React 树中进行动画处理。
- 用动画响应手势。
- 添加拖动、平移、悬停和点击手势。
以下是一个例子:
<motion.div
animate={{ rotate: 360 }}
transition={{ duration: 2 }}
/>
➡animation
道具。
正如你在上面的代码片段中看到的,motion
组件通过 prop 进行动画处理animate
。当 animate 中的任何值发生变化时,组件将自动动画到更新的目标。
如果使用x
或scale
值,则它们将通过弹簧模拟进行动画。而像opacity
或 这样的值color
将使用补间动画。
您可以通过传递transition
道具来设置不同类型的动画。
以下是一个例子:
<motion.div
animate={{ x: 100 }}
transition={{ ease: "easeOut", duration: 2 }}
/>
➡手势。
所有motion
组件都可以检测悬停、点击、平移和拖动手势。每个组件都有可以附加的事件监听器。
motion
该组件提供的两个常用手势道具是whileHover
和whileTap
。
以下是一个例子:
motion.button
whileHover={{
scale: 1.2,
transition: { duration: 1 },
}}
whileTap={{ scale: 0.9 }}
/>
➡运动值。
用于跟踪动画值的状态和速度。这些是自动创建的。但对于高级用例,可以手动创建。
它允许您:
- 设置和获取状态。
- 通过钩子链接 MotionValues
useTransform
。 - 传递给多个组件以同步它们之间的运动。
以下是一个例子:
export function MyComponent() {
const x = useMotionValue(0)
return <motion.div style={{ x }} />
}
我们会做什么?😏

是的!我们采用了创建 React 应用时提供的样板界面,并添加了一些有趣的交互元素。如您所见,以下是一些正在发生的事情:
- 首先,当页面加载时,它会淡入。这是唯一发生的动画。
- 接下来是交互。点击 React 徽标时,我们可以看到它像一个按钮一样。鼠标按下时,它会弹回;鼠标释放时,它会恢复正常状态。
- 我们还可以单击并水平拖动 React 徽标,它会随着远离中心而不断消失。
- 当鼠标悬停在徽标下方时,其文字会放大。
- 为了水平移动文本的位置,我们有一个滑块可以控制它。
- 最后,我们可以使用切换按钮淡入或淡出相同的文本。
内容太多了,赶紧进入开发环节吧!
步骤 1:创建 React 项目并添加 Framer Motion
创建完React 应用程序后,只需使用以下命令安装 Framer Motion 依赖项:
npm i framer-motion
第 2 步:导入库并转换元素!
对于这个演示,我们需要import
这三个 API 函数:motion
,,useMotionValue
。useTransform
import { motion, useMotionValue, useTransform } from 'framer-motion';
我们已经讨论过前两个。现在,useTransform
我们可以通过一个钩子将最新的 MotionValue 传递给一个更新函数,该函数获取最新的父值并对其进行转换。
导入后,我们需要将 React 样板文件自带的一些默认 HTML 标签更改为新的 Framer Motion 标签。在 App.js中执行以下更改:
- 父
<div>
元素为<motion.div>
。 - 将 React 徽标
<img>
标签包装在新创建的<motion.div>
. - 标签
<p>
为<motion.p>
。 - 添加一个新
<input>
元素,它将成为我们的范围滑块,其min
和max
值分别为-100
和100
。 - 接下来创建一个新的
<motion.button>
文本为“Toggle Fade”。
以下是我们目前所做的工作:
<motion.div className='App'>
<header className='App-header'>
<motion.div>
<img src={logo} className='App-logo' alt='logo' />
</motion.div>
<motion.p>
Edit <code>src/App.js</code> and save to reload.
</motion.p>
<input
type='range'
name='range'
min='-100'
max='100'
/>
<motion.button className='toggle-button'>
Toggle Fade
</motion.button>
</header>
</motion.div>
由于我们尚未编写任何道具,并且运动代码没有可用的属性,因此什么也不会发生。
步骤 3:添加动画和过渡!
页面淡入淡出动画:
对于初始淡入淡出动画,我们使用新的initial
、animate
和属性。transition
motion.div
- 为初始化
initial
一个值animate
。 - 具有
animate
动画的实际值 - 用于
transition
添加从一帧变化到另一帧的默认过渡。
由于我们需要一个简单的淡入淡出动画,其中动画发生半秒,我们赋予以下属性motion.div
:
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
现在整个页面都消失了!

React Logo 上的点击和拖动交互:
这是通过组件上的whileTap
辅助drag
动画道具实现的motion
。
因此,点击徽标时,我们首先需要它稍微缩放一下,因此我们将scale
属性添加到whileTap
prop 中。对于拖动,我们需要传递要在哪个轴上进行拖动。在这里,我们水平拖动,所以是x
轴。
x
为了获得我们传入prop的 的实际值drag
,我们将使用一个useMotionValue
钩子来跟踪被拖动元素的状态和速度。最初,我们不希望启用拖动功能,因此我们传入了0
。
至于定义拖拽坐标,钩子会帮我们实现useTransform
。通过钩子,我们可以传入x
轴的最新值。这个值可以是任意数字,具体取决于你想要实现的拖拽的开销。
const x = useMotionValue(0);
const opacity = useTransform(x, [-200, 0, 200], [0, 1, 0]);
现在,为了使这两个功能正常工作,我们需要传递style
prop,该 prop 接收我们上面提供的不同常量。因此,我们的图像拖动和点击交互代码如下所示:
const x = useMotionValue(0);
const opacity = useTransform(x, [-200, 0, 200], [0, 1, 0]);
.
.
.
<motion.div whileTap={{ scale: 0.9 }} drag='x' style={{ x, opacity }}>
<img src={logo} className='App-logo' alt='logo' />
</motion.div>
.
.
.
现在这个交互有效了!

文本互动:
我们在悬停和点击时有一个刻度,在移动滑块时有一个拖动,最后使用按钮完成淡入淡出切换。
缩放的操作与点击完全相同,只是这里的交互既包括点击也包括悬停,因此对于新的悬停交互,我们使用whileHover
道具。
该x
变量用于水平拖动,因为我们需要相同的值。现在,为了约束它的值,我们可以使用dragConstraints
prop 对其进行微调,该 prop 允许我们传递拖动手势的left
和约束。right
对于最终的交互,我们需要使用useState
React Hook 来改变文本的拖动和淡入淡出状态。因此,我们为状态定义了以下两个变量:
const [value, setValue] = useState(0);
const [toggle, setToggle] = useState(1);
<input />
在我们一开始创建的元素上,它的onChange
事件使用了HooksetValue()
中的方法useState
,我们传入用户拖动滑块时选择的当前值。 的 上也会触发类似的事件,<motion.button>
但onClick
这里我们通过0
交换1
和 的状态来切换。
为了实现实际的淡入淡出,我们只需value
从创建状态中获取(添加'px'
字符串,使其作为实际的像素单位工作)并使用opacity
等于toggle
我们创建的值。
const [value, setValue] = useState(0);
const [toggle, setToggle] = useState(1);
.
.
.
<motion.p animate={{ x: value + 'px', opacity: toggle }}
drag='x'
dragConstraints={{ left: -100, right: 100 }}
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}>
Edit <code>src/App.js</code> and save to reload
</motion.p>
<input type='range' name='range' min='-100' max='100'
value={value}
onChange={(e) => setValue(e.target.value)} />
<motion.button onClick={() => setToggle((prevValue)
=> (prevValue ? 0 : 1))}
className='toggle-button'>Toggle Fade
</motion.button>
.
.
.
按钮样式在 CSS 中很简单,比默认样式看起来更好:
.toggle-button {
margin-top: 1.5em;
width: 10em;
border: 0;
outline: none;
padding: 1em;
border-radius: 10em;
font-weight: bold;
}
.toggle-button:hover {
color: #282c34;
background-color: #61dafb;
}
现在我们的最终交互也有效了!

如果你对这个库不感冒,可以看看 React Spring。我写了一篇相关的教程:
谢谢阅读,我非常感激!祝你拥有美好的一天。(✿◕‿◕✿)
如果你想给开发者留下深刻印象,可以尝试新的开源 Windows 终端。😎 在此处下载:https://t.co/bZQ78xBBr7
— 英国微软开发者 (@msdevUK) 2020 年 10 月 15 日
图片来源:https://t.co/GsUA5a7mlf #DevHumour pic.twitter.com/WQfKOWTjfa