前端开发 / 使用 Framer Motion 为应用添加动画效果
在 React 项目中,使用 Framer Motion 库来添加动画效果。
Framer Motion 简介
什么是 Framer Motion
Framer Motion 是一个用于 React 的开源动画库。它以简洁、直观的 API 为 React 组件提供了强大的动画和交互能力。
该库的背后是Framer,一个流行的原型设计工具,但 Framer Motion 可以作为一个独立的库用于任何 React 项目。
Framer Motion 官方网站: https://www.framer.com/motion/
Framer Motion 的优点
Framer Motion 相当年轻,初次发布是在 2019 年。
相较于其他用于实现前端动画的工具,它具有以下优点:
- 直观的 API: Framer Motion 的 API 非常直观和人性化,特别是对于 React 开发者来说。它使用了 React 的道具( props )系统,使得为组件添加动画和交互变得十分简单。
- 物理动画: Framer Motion 支持基于真实物理的动画,如弹簧。这些动画不仅看起来更自然,而且不需要复杂的配置。
- 自动布局动画:当组件在屏幕上的位置改变时, Framer Motion 可以自动地为它提供平滑的过渡效果,无需任何额外的配置。
- 良好的社区支持和文档: Framer Motion 拥有一个积极的社区,提供了丰富的资源和很好的文档支持。
- 性能:与其他动画库相比, Framer Motion 注重性能优化,使其在多数设备上都能流畅运行。
- 专为 React 设计:与一些其他通用的前端动画库相比, Framer Motion 是专门为 React 设计的,这使得它与 React 的工作方式完美结合。
Framer Motion 能实现什么效果
你可以在这里预览 Framer Motion 动画效果: https://www.framer.com/motion/examples/
使用 Framer Motion ,你可以实现以下效果(但不仅限于此):
- 基础动画:例如淡入、淡出、缩放、旋转、移动等。
- 拖放交互:可以为组件添加拖动功能,并定义拖动的方向、约束等。
- 基于物理的动画:例如弹簧效果,它可以使动画更自然和生动。
- 布局动画:当组件的布局改变时(例如,一个列表项从一个位置移动到另一个位置), Framer Motion 可以自动地为其提供过渡效果。
- SVG 路径动画:可以轻松地为 SVG 路径创建动画效果。
- 复杂序列动画:使用它的动画控制和变种( variants )系统,你可以定义复杂的动画序列,而不会使代码变得混乱。
- 共享布局转换:当两个不同的组件有相同的视觉元素时(例如,一个列表项变成了一个详情页的头部), Framer Motion 可以在这两个组件之间创建无缝的动画过渡。
安装 Framer Motion
Framer Motion 需要 React 18 或更高版本。
通过 npm 安装:
npm install framer-motion --legacy-peer-deps
安装后,您可以通过 framer-motion
导入 Framer Motion :
import { motion } from "framer-motion"
Motion 组件( motion.div )
示例代码
<motion.div
initial={{ opacity: 0.5, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
transition={{
duration: 0.8,
// delay: 0.5,
ease: [0, 0.71, 0.2, 1.01],
}}
//whileInView={{ opacity: 1, scale: 1 }} // 和 animate 用法一样
//viewport={{ once: true }}
whileHover={{ scale: 1.05 }}
>
animate
:定义动画的目标或最终状态。您可以在这里设置任何您想要的属性值,例如透明度、比例、旋转等。initial
:定义动画的初始状态。当组件首次渲染时,它会开始于这个状态。transition
:定义从初始状态到动画状态的过渡效果。这里可以设置过渡的持续时间、延迟、缓动函数等
animate | 动画最终状态
<motion.div animate={{ x: 100 }} />
transition |过渡效果
官方文档: https://www.framer.com/motion/transition/
Motion 组件动画效果模板收集
Option 1.从下到上出现
<motion.div
initial={{ translateY: "50%", opacity: 0.1 }}
whileInView={{ translateY: "0%", opacity: 1 }}
viewport={{ once: true }}
transition={{
duration: 0.8,
// ease: [0, 0.71, 0.2, 1.01], // 轻微减速效果
ease: [0.2, 0.88, 0.32, 1.1], // 回弹效果
}}
// whileHover={{ scale: 1.05 }}
>
Option 2.放大出现
<motion.div
initial={{ opacity: 0, scale: 0.5 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{
duration: 0.8,
ease: [0, 0.71, 0.2, 1.01],
}}
// whileHover={{ scale: 1.05 }}
>
Option 3. 模糊出现
<motion.div
initial={{ opacity: 1, scale: 0.8, filter: "blur(10px)" }}
whileInView={{ opacity: 1, scale: 1, filter: "blur(0px)" }}
// viewport={{ once: true }}
transition={{
duration: 0.5,
ease: [0, 0.5, 0.8, 1],
}}
// whileHover={{ scale: 1.05 }}
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
>
Option 4.从下到上+模糊混合
<motion.div
initial={{ translateY: "50%", opacity: 0.5, filter: "blur(20px)" }}
whileInView={{
translateY: "0%",
opacity: 1,
scale: 1,
filter: "blur(0px)",
}}
viewport={{ once: true }}
transition={{
duration: 0.5,
ease: [0.2, 0.88, 0.32, 1.1], // 回弹效果
}}
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
>
设置页面首次加载时,不应用效果
检测元素何时进入视窗( Scroll-triggered )
Famer Motion 提供了 3 种方法来处理元素进入窗口时的动作:
方法 | 特点 | 劣势 |
---|---|---|
whileInView 👍 | – 动画属性( animation prop ) – 使用最简单的 API ,最常用 | – 无法实现更高自定义要求 |
useInView | – React Hook – 可以和其他 React 状态结合使用 | – 使用比 whileInView 复杂 |
inView | – React Hook – 基于浏览器的本机 API 构建,可实现最佳性能/最小文件 | – 使用最复杂 |
whileInView 方法
官方文档地址: https://www.framer.com/motion/scroll-animations/#scroll-triggered-animations
使用示例:
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
// whileHover={{ scale: 1.05 }}
>
viewport | 常结合使用
官方文档地址: https://www.framer.com/motion/scroll-animations/##viewport-options
once:true
只触发一次效果
onViewportEnte | 进入时的回调
TODO
onViewportLeave | 离开时的回调
TODO
常见问题
Error: Replace exitBeforeEnter with mode=’wait’
Framer Motion 中的 exitBeforeEnter
属性可确保,前一个组件在加载下一个组件及其各自的动画之前被卸载,这样组件之间的更改将是无缝的。
属性 exitBeforeEnter
在新版中已被弃用,替换为 mode='wait'
即可。
更多说明可以参考官方文档: https://www.framer.com/motion/animate-presence/###mode
Framer Motion 基础知识
AnimatePresence 和 motion 组件的作用
示例代码:
return (
<AnimatePresence mode="wait">
{open && (
<motion.div
initial="hidden"
animate="visible"
exit="exit"
variants={modalVariants}
className="fixed inset-0 z-10 overflow-y-auto"
role="dialog"
aria-modal="true"
>
<div className="flex min-h-screen items-end justify-center px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<div
className="fixed inset-0 transition-opacity"
onClick={closeModal}
>
<div className="absolute inset-0 bg-gray-900 opacity-75" />
</div>
<span className="hidden sm:inline-block sm:h-screen sm:align-middle" />
<motion.div className="inline-block transform overflow-hidden overflow-y-auto rounded-lg bg-white text-left align-bottom shadow-xl transition-all max-h-[90vh] sm:w-full sm:max-w-md sm:align-middle 2xl:max-w-lg">
{children}
<CloseButton onClick={closeModal} />
</motion.div>
</div>
</motion.div>
)}
</AnimatePresence>
);
};
motion
和 AnimatePresence
在 framer-motion 的实践中经常一起使用。
例如,当你有一个条件渲染的模态框或路由切换的页面时,你可能想为这些元素添加平滑的进入和离开动画。
在这种情况下:
motion
组件提供了动画的具体细节。AnimatePresence
确保了在元素被移除之前可以执行适当的退出动画。
所以,尽管你可以单独使用它们,但它们经常一起使用来实现更复杂的动画效果。
motion
motion
是 framer-motion 的核心组件之一,提供了一种简单的方法来为 React 组件添加动画。例如,你可以将标准的 div
替换为 motion.div
,然后为其提供一些动画属性和方法,从而使该 div
具有动画效果。
使用场景:使用 motion
当你想要给一个元素添加动画。
AnimatePresence
AnimatePresence
是一个包裹器组件,用于侦测其子组件何时进入或离开 DOM 。当它检测到子组件被移除时,它允许子组件(通常是 motion
组件)执行定义的退出动画。
使用场景:使用 AnimatePresence
当你想要处理元素的进入和退出动画,尤其是在该元素可能会突然出现或消失的情况下。