使用 Framer motion 在 NextJS 中创建出色的页面过渡效果
我最近决定用 NextJs 重新设计我的作品集。于是我开始在网上搜索一些很酷的页面过渡效果,希望能用在我的作品集上,然后我偶然发现了这个类似的效果。(类似于Barba.js)
所以,我决定弄清楚并创建这个过渡效果。在本教程中,我将讲解创建这个漂亮的页面过渡效果的步骤。
让我们开始吧。
注意:本例中,我仅讨论与动画相关的 CSS。如果您也需要完整的 CSS,请参阅本教程末尾提到的 GitHub 代码库。
新项目,哇喔!!
首先,我们需要通过在终端中输入以下命令来创建一个新的 NextJS 项目。
npx create-next-app nextjs-page-transition-example
现在,在您最喜欢的编辑器中打开新创建的项目文件夹。
在终端中输入npm run dev
以在端口 3000 上启动开发服务器。
安装 Framer motion
键入npm install framer-motion --save
以将框架运动安装到您的项目中。
一些设置
现在我们已经安装了 framer motion,接下来需要进行一些设置。打开pages 目录中的_app.js文件,从 framer-motion 中导入AnimatePresence,并将其包裹在主内容周围,如下所示。
import "../styles/globals.css";
import { AnimatePresence } from "framer-motion";
function MyApp({ Component, pageProps, router }) {
return (
<AnimatePresence exitBeforeEnter>
<Component {...pageProps} key={router.route} />
</AnimatePresence>
);
}
export default MyApp;
AnimatePresence 有助于在 React 组件从 React 树中移除时为其添加动画效果。它有助于制作组件的退出动画。AnimatePresence的exitBeforeEnter属性指示 framer-motion 使用动画移除当前组件,然后启动新组件的动画。
创建页面
现在,我们需要创建不同的页面,以便在它们之间实现过渡动画。在本例中,我们将创建三个简单的页面(主页、关于、服务)。
打开pages 目录中的index.js ,并创建一个基本的 React 组件。
function Home() {
return (
<main>
<h1>Home Page</h1>
</main>
);
}
export default Home;
现在,我们需要像这样创建另外两个文件about.js和services.js 。
function Services() {
return (
<main>
<h1>Services Page</h1>
</main>
);
}
export default Services;
function Services() {
return (
<main>
<h1>Services Page</h1>
</main>
);
}
export default Services;
创建导航栏
现在我们已经创建了三个基本页面,我们需要一个带有链接的导航栏,以便页面之间切换。在根目录中创建一个名为components
的文件夹,并在该文件夹中创建包含以下内容的Navbar.js文件。
import Link from "next/link";
export default function Navbar() {
return (
<nav className="navbar">
<div className="container">
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<Link href="/services">Services</Link>
</div>
</nav>
);
}
这是一个基本的导航栏,用于在页面之间导航。Link是一个内置的 NextJS模块,它会在 DOM 中创建一个链接,用于导航到其他页面。
现在,我们需要将导航栏导入到我们创建的页面中!最终的文件应该看起来像这样。
function Home() {
return (
<main>
<h1>Home Page</h1>
</main>
);
}
export default Home;
function About() {
return (
<main>
<h1>About Page</h1>
</main>
);
}
export default About;
function Services() {
return (
<main>
<h1>Services Page</h1>
</main>
);
}
export default Services;
动画页面——有趣的部分
我们先来理解一下动画。这个动画分为两部分:当前页面的滑入动画和下一页的滑出动画。为了更好地理解,请看下图。
第一页的滑入动画 第二页的滑出动画
我们需要为每个需要动画的页面添加两个 div(一个用于滑入动画,另一个用于滑出动画)。我们可以为这两个 div 创建一个组件,但将这两个 div 添加到每个页面可能会很麻烦,所以我们将为此创建一个“高阶组件” 。
HOC
创建一个名为 HOC 的文件夹,并在其中创建一个名为withTransition.js的文件。在这个文件中,我们将从 framer motion 导入 motion ,并创建一个函数,该函数将返回一个包含动画 div 的新组件。
import { motion } from "framer-motion";
const withTransition = (OriginalComponent) => {
return () => (
<>
<OriginalComponent />
<motion.div
className="slide-in"
initial={{ scaleX: 0 }}
animate={{ scaleX: 0 }}
exit={{ scaleX: 1 }}
transition={{ duration: 1, ease: "easeInOut" }}
/>
<motion.div
className="slide-out"
initial={{ scaleX: 1 }}
animate={{ scaleX: 0 }}
exit={{ scaleX: 0 }}
transition={{ duration: 1, ease: "easeInOut" }}
/>
</>
);
};
export default withTransition;
.slide-in {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100%;
background: #066bb8;
transform-origin: left;
}
.slide-out {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100%;
background: #066bb8;
transform-origin: right;
}
现在,我们需要在每个需要页面过渡的页面中添加这个 HOC。例如,我想为所有 3 个页面添加动画,那么我需要在每个页面中导入withTransition,并像下面这样传递组件。
import Navbar from "../components/Navbar";
import withTransition from "../HOC/withTransition";
function Home() {
return (
<>
<Navbar />
<main>
<h1>Home Page</h1>
</main>
</>
);
}
export default withTransition(Home);
import Navbar from "../components/Navbar";
import withTransition from "../HOC/withTransition";
function About() {
return (
<>
<Navbar />
<main>
<h1>About Page</h1>
</main>
</>
);
}
export default withTransition(About);
import Navbar from "../components/Navbar";
import withTransition from "../HOC/withTransition";
function Services() {
return (
<>
<Navbar />
<main>
<h1>Services Page</h1>
</main>
</>
);
}
export default withTransition(Services);
就是这样....🎊️
至此,页面过渡效果已完成。演示及 GitHub 链接如下:
演示 - https://nextjs-transition-example.vercel.app/
GitHub 仓库 - https://github.com/shaan71845/nextjs-page-transition-example
请随意留下🌠️
感谢您的阅读!!