使用 Framer Motion 实现 Next.js 页面过渡动画

2025-05-25

使用 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 提供的各种动画

阅读有关 Framer Motion 的更多信息并在其网站上查看示例。


Next.js 页面转换动画

除了制作用户触发的动画外,Framer Motion 还可以在组件挂载(进入)和卸载(离开)时为其添加动画。我使用此功能来为页面变化时出现的组件添加动画。用 Next.js 的术语来说,这指的是除页面之外的所有组件_app.js——所有页面和其他组件。在可能的情况下,使用_app.jsFramer Motion 在页面变化之间持久化布局可以减少 React 每次页面变化时需要进行的渲染量,从而潜在地提升应用性能。

准备代码库

在我向网站添加任何动画之前,我做了两项重构:

  1. 将那些不应该在每次页面更改时都动画的常用组件移到了 中_app.js。就我而言,这意味着将Header和移到 中Footer,你可以在 GitHub 上看到它们。

  2. 添加了一个包装器组件来控制页面内的动画状态。在我的网站上,它是Layout组件。请注意,该<motion.main>组件是 Framer Motion 特有的。在渲染的 HTML 输出中,它将是一个 HTMLmain元素,但是,添加motion.Framer Motion 提供的 可以传递某些动画属性,例如transitioninitialanimate

 进入动画

查看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 },
}


Enter fullscreen mode Exit fullscreen mode

现在关注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>


Enter fullscreen mode Exit fullscreen mode

initial状态animate将控制此组件的进入动画。当您在我的网站上切换页面时,您应该会看到内容从不透明度为0x位置为变为不-200px透明度为1并位于屏幕中心。这会产生内容从左侧淡入的效果。顺便说一句,“Transition 是一个定义值如何从一个状态动画到另一个状态的对象”——摘自 Framer Motion 网站

进入动画很棒,但让我们更进一步,在组件离开页面时为其添加动画。

添加AnimatePresence和退出动画

Framer Motion 的一个特性是,它可以在组件离开 React DOM 后继续动画。要激活此功能,您可以使用该AnimatePresence组件。在我的网站上,我使用可选的exitBeforeEnterprop,它告诉进入动画等到退出动画结束后再开始——如果没有这个 prop,内容就会挂载到正在卸载的内容之上,看起来很乱。

您需要将AnimatePresence组件添加到_app.js文件中,使其永不卸载(卸载会禁用退出动画)。另请注意,initial={false}首次访问网站时禁用进入动画的 prop。禁用它只是个人偏好,如果您想启用它,请删除该行。

AnimatePresence添加到_app.js,即可exitmotion.main组件添加动画。请参阅上面的两个代码块。

我们快完成了,但我们只需要修复当路线改变时 Next.js 滚动到页面顶部的问题。

解决链接更改时的滚动问题

在向 Next.js 应用程序添加页面导航时,您应该使用该Link组件。默认情况下,Link单击该组件时,它会在动画之前滚动到页面顶部,这会使页面转换看起来有些笨拙。如下所示:


动画前滚动到顶部

幸运的是,解决这个问题相当简单。Link在你的代码库中使用的每个组件上,添加一个prop。这将在点击时禁用滚动。为了简化操作并保持代码简洁,我创建了一个包裹但禁用滚动的scroll={false}组件。我调用了它,你可以在 GitHub 上查看LinkNoScrollLink

禁用Link组件的滚动功能后,建议在 Framer Motion 退出动画完成后滚动到页面顶部。这样可以实现内容离开当前滚动高度,但新内容进入页面顶部的效果。同样,这很简单,您可以在中的组件上使用onExitComplete属性。以下代码片段将在退出动画完成后滚动到页面顶部。AnimatePresence_app.js



onExitComplete={() => window.scrollTo(0, 0)}


Enter fullscreen mode Exit fullscreen mode

在 GitHub 上查看

补充一点,当您更改页面时,Framer Motion 应该卸载旧内容,滚动到顶部并安装新内容。


成品

如果您一直在关注或想要在我的网站上实时观看,您将看到以下页面转换:


完成的页面动画


概括

在本文中,我希望帮助其他人借助 Framer Motion 为他们的 Next.js 应用添加页面过渡效果。在将它们添加到我的网站时,我克服了一些障碍,例如意识到AnimatePresence需要添加过渡效果_app.js,以及如何在点击按钮后停止滚动到页面顶部Link

如果您有任何补充或只是想表示感谢,请发表评论或做出回应!

感谢阅读!

文章来源:https://dev.to/jameswallis/animating-next-js-page-transitions-with-framer-motion-1g9j
PREV
我使用 Dev.to 作为 CMS 彻底重写了我的个人网站
NEXT
不健康的代码:到处都是空值检查!识别问题解决方案:空对象模式如何保持代码健康保持联系导航你的软件开发职业通讯