使用 Framer Motion 实现 Next.js 页面过渡动画
几个月前,我从零开始重建了我的 Dev.to 驱动的 Next.js 网站。在构建过程中,我决定添加动画效果,让它简单的设计更加生动。之前,我使用 CSS 过渡和 JavaScript 来实现网页动画。这次,我想使用一个为 React.js 构建的动画库,以便在未来的项目中使用。
输入 Framer Motion。
帧运动
适用于 React 的生产级运动库。
- https://www.framer.com/motion
它是一个库,可以在页面上以及组件进入和离开时实现 React 组件的动画。
Framer Motion 可以执行以下所有操作:
- 弹簧动画
- 简单关键帧语法
- 手势(拖动/点击/悬停)
- 布局和共享布局动画
- SVG 路径
- 退出动画
- 服务器端渲染
- 跨组件编排动画的变体
- CSS 变量
并可以使静态页面变得生动:
阅读有关 Framer Motion 的更多信息并在其网站上查看示例。
Next.js 页面转换动画
除了制作用户触发的动画外,Framer Motion 还可以在组件挂载(进入)和卸载(离开)时为其添加动画。我使用此功能来为页面变化时出现的组件添加动画。用 Next.js 的术语来说,这指的是除页面之外的所有组件_app.js
——所有页面和其他组件。在可能的情况下,使用_app.js
Framer Motion 在页面变化之间持久化布局可以减少 React 每次页面变化时需要进行的渲染量,从而潜在地提升应用性能。
准备代码库
在我向网站添加任何动画之前,我做了两项重构:
-
将那些不应该在每次页面更改时都动画的常用组件移到了 中
_app.js
。就我而言,这意味着将Header
和移到 中Footer
,你可以在 GitHub 上看到它们。 -
添加了一个包装器组件来控制页面内的动画状态。在我的网站上,它是
Layout
组件。请注意,该<motion.main>
组件是 Framer Motion 特有的。在渲染的 HTML 输出中,它将是一个 HTMLmain
元素,但是,添加motion.
Framer Motion 提供的 可以传递某些动画属性,例如transition
、initial
和animate
。
进入动画
查看Layout
组件,您将看到一个名为variants
(见下文) 的对象。变体通过消除向组件添加动画对象的要求来提升代码的简洁性。您可以在Framer Motion 网站motion.main
上阅读更多相关信息。
const variants = {
hidden: { opacity: 0, x: -200, y: 0 },
enter: { opacity: 1, x: 0, y: 0 },
exit: { opacity: 0, x: 0, y: -100 },
}
现在关注motion.main
组件:
<motion.main
variants={variants} // Pass the variant object into Framer Motion
initial="hidden" // Set the initial state to variants.hidden
animate="enter" // Animated state to variants.enter
exit="exit" // Exit state (used later) to variants.exit
transition={{ type: 'linear' }} // Set the transition to linear
className=""
>
{children}
</motion.main>
initial
和状态animate
将控制此组件的进入动画。当您在我的网站上切换页面时,您应该会看到内容从不透明度为0
和x
位置为变为不-200px
透明度为1
并位于屏幕中心。这会产生内容从左侧淡入的效果。顺便说一句,“Transition 是一个定义值如何从一个状态动画到另一个状态的对象”——摘自 Framer Motion 网站。
进入动画很棒,但让我们更进一步,在组件离开页面时为其添加动画。
添加AnimatePresence
和退出动画
Framer Motion 的一个特性是,它可以在组件离开 React DOM 后继续动画。要激活此功能,您可以使用该AnimatePresence
组件。在我的网站上,我使用可选的exitBeforeEnter
prop,它告诉进入动画等到退出动画结束后再开始——如果没有这个 prop,内容就会挂载到正在卸载的内容之上,看起来很乱。
您需要将AnimatePresence
组件添加到_app.js
文件中,使其永不卸载(卸载会禁用退出动画)。另请注意,initial={false}
首次访问网站时禁用进入动画的 prop。禁用它只是个人偏好,如果您想启用它,请删除该行。
AnimatePresence
添加到后_app.js
,即可exit
为motion.main
组件添加动画。请参阅上面的两个代码块。
我们快完成了,但我们只需要修复当路线改变时 Next.js 滚动到页面顶部的问题。
解决链接更改时的滚动问题
在向 Next.js 应用程序添加页面导航时,您应该使用该Link
组件。默认情况下,Link
单击该组件时,它会在动画之前滚动到页面顶部,这会使页面转换看起来有些笨拙。如下所示:
幸运的是,解决这个问题相当简单。Link
在你的代码库中使用的每个组件上,添加一个prop。这将在点击时禁用滚动。为了简化操作并保持代码简洁,我创建了一个包裹但禁用滚动的scroll={false}
组件。我调用了它,你可以在 GitHub 上查看。Link
NoScrollLink
禁用Link
组件的滚动功能后,建议在 Framer Motion 退出动画完成后滚动到页面顶部。这样可以实现内容离开当前滚动高度,但新内容进入页面顶部的效果。同样,这很简单,您可以在中的组件上使用onExitComplete
属性。以下代码片段将在退出动画完成后滚动到页面顶部。AnimatePresence
_app.js
onExitComplete={() => window.scrollTo(0, 0)}
补充一点,当您更改页面时,Framer Motion 应该卸载旧内容,滚动到顶部并安装新内容。
成品
如果您一直在关注或想要在我的网站上实时观看,您将看到以下页面转换:
概括
在本文中,我希望帮助其他人借助 Framer Motion 为他们的 Next.js 应用添加页面过渡效果。在将它们添加到我的网站时,我克服了一些障碍,例如意识到AnimatePresence
需要添加过渡效果_app.js
,以及如何在点击按钮后停止滚动到页面顶部Link
。
如果您有任何补充或只是想表示感谢,请发表评论或做出回应!
感谢阅读!
文章来源:https://dev.to/jameswallis/animating-next-js-page-transitions-with-framer-motion-1g9j