诚之和:如何在 Next.js 项目中制作自定义加载屏幕

本文介绍了如何在 Next.js 项目中构建自定义加载屏幕组件,通过利用 Next.js 的路由事件监听,实现页面路由变化时显示加载屏幕。详细步骤包括组件样式设计、事件监听以及在 app.js 中的实现方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

介绍

Next.js 是一个建立在 Node.js 之上的开源开发框架,支持基于 React 的 Web 应用程序功能,例如服务器端渲染和生成静态网站。

我试图在 Next.js 中为我的项目构建一个自定义加载屏幕,所以我尝试谷歌我们如何实现它,经过数小时的搜索,我无法找到适合我需要的解决方案。我在互联网上遇到了一个解决方案,它使用一个名为“nprogress”的库来执行此操作,但它没有提供我想要实现的加载屏幕,因此在浏览 Next.js 文档和这个“nprogress”解决方案后,我能够找出解决问题的方法。我花了很多时间,所以我创建了这个博客来帮助任何想要在更短的时间内轻松地在 Next.js 中实现自定义加载屏幕的人。

制作自定义加载屏幕组件

这部分完全取决于您以及您希望加载屏幕组件的外观。例如下面是我的加载组件:

<span style="color:#333333"><span style="background-color:#ffffff"><span style="background-color:#201e2f"><span style="color:#f8f8f2"><code><span style="color:#f92672">import</span> React <span style="color:#f92672">from</span> <span style="color:#e6db74">"</span><span style="color:#e6db74">react</span><span style="color:#e6db74">"</span>;
<span style="color:#f92672">import</span> styles <span style="color:#f92672">from</span> <span style="color:#e6db74">"</span><span style="color:#e6db74">./Loading.module.css</span><span style="color:#e6db74">"</span>;

<span style="color:#f92672">function</span> <span style="color:#a6e22e">Loading</span>(<span style="color:#f8f8f2">props</span>) {
  <span style="color:#f92672">return</span> (
    <span style="color:#f8f8f2 !important"><</span><span style="color:#f8f8f2 !important"><span style="color:#f92672">div</span></span> <span style="color:#f8f8f2 !important"><span style="color:#f92672">className</span></span><span style="color:#f8f8f2 !important">=</span><span style="color:#f8f8f2 !important"><span style="color:#e6db74">{</span></span><span style="color:#f8f8f2 !important"><span style="color:#e6db74">props</span></span><span style="color:#f8f8f2 !important"><span style="color:#e6db74">.</span></span><span style="color:#f8f8f2 !important"><span style="color:#e6db74">loading</span></span> <span style="color:#f8f8f2 !important">?</span> <span style="color:#f8f8f2 !important"><span style="color:#f92672">styles</span></span><span style="color:#f8f8f2 !important"><span style="color:#f92672">.</span></span><span style="color:#f8f8f2 !important"><span style="color:#f92672">body_loading</span></span> <span style="color:#f8f8f2 !important"><span style="color:#f92672">:</span></span> <span style="color:#f8f8f2 !important"><span style="color:#f92672">styles</span></span><span style="color:#f8f8f2 !important"><span style="color:#f92672">.</span></span><span style="color:#f8f8f2 !important"><span style="color:#f92672">none</span></span><span style="color:#f8f8f2 !important">}</span><span style="color:#f8f8f2 !important">></span>
      <span style="color:#f8f8f2 !important"><</span><span style="color:#f8f8f2 !important"><span style="color:#f92672">div</span></span>
        <span style="color:#f8f8f2 !important"><span style="color:#f92672">className</span></span><span style="color:#f8f8f2 !important">=</span><span style="color:#f8f8f2 !important"><span style="color:#e6db74">{</span></span><span style="color:#f8f8f2 !important"><span style="color:#e6db74">styles</span></span><span style="color:#f8f8f2 !important"><span style="color:#e6db74">.</span></span><span style="color:#f8f8f2 !important"><span style="color:#e6db74">lds_ellipsis</span></span><span style="color:#f8f8f2 !important"><span style="color:#e6db74">}</span></span>
      <span style="color:#f8f8f2 !important">></span>
        <span style="color:#f8f8f2 !important"><</span><span style="color:#f8f8f2 !important"><span style="color:#f92672">div</span></span><span style="color:#f8f8f2 !important">></span><span style="color:#f8f8f2 !important"><</span><span style="color:#f8f8f2 !important">/<span style="color:#f92672">div</span></span><span style="color:#f8f8f2 !important">></span>
        <span style="color:#f8f8f2 !important"><</span><span style="color:#f8f8f2 !important"><span style="color:#f92672">div</span></span><span style="color:#f8f8f2 !important">></span><span style="color:#f8f8f2 !important"><</span><span style="color:#f8f8f2 !important">/<span style="color:#f92672">div</span></span><span style="color:#f8f8f2 !important">></span>
        <span style="color:#f8f8f2 !important"><</span><span style="color:#f8f8f2 !important"><span style="color:#f92672">div</span></span><span style="color:#f8f8f2 !important">></span><span style="color:#f8f8f2 !important"><</span><span style="color:#f8f8f2 !important">/<span style="color:#f92672">div</span></span><span style="color:#f8f8f2 !important">></span>
        <span style="color:#f8f8f2 !important"><</span><span style="color:#f8f8f2 !important"><span style="color:#f92672">div</span></span><span style="color:#f8f8f2 !important">></span><span style="color:#f8f8f2 !important"><</span><span style="color:#f8f8f2 !important">/<span style="color:#f92672">div</span></span><span style="color:#f8f8f2 !important">></span>
      <span style="color:#f8f8f2 !important"><</span><span style="color:#f8f8f2 !important">/<span style="color:#f92672">div</span></span><span style="color:#f8f8f2 !important">></span>
    <span style="color:#f8f8f2 !important"><</span><span style="color:#f8f8f2 !important">/<span style="color:#f92672">div</span></span><span style="color:#f8f8f2 !important">></span>
  );
}

<span style="color:#f92672">export</span> <span style="color:#f92672">default</span> Loading;</code></span></span></span></span>

加载组件的样式 (CSS):

<span style="color:#333333"><span style="background-color:#ffffff"><span style="background-color:#201e2f"><span style="color:#f8f8f2"><code><span style="color:#a6e22e">.body_loading</span> {
  <span style="color:#66d9ef">display</span>: flex;
  <span style="color:#66d9ef">align-items</span>: center;
  <span style="color:#66d9ef">justify-content</span>: center;
  <span style="color:#66d9ef">height</span>: <span style="color:#ae81ff">100vh</span>;
}
<span style="color:#a6e22e">.none</span> {
  <span style="color:#66d9ef">display</span>: none;
}
<span style="color:#a6e22e">.lds_ellipsis</span> {
  <span style="color:#66d9ef">display</span>: inline-block;
  <span style="color:#66d9ef">position</span>: relative;
  <span style="color:#66d9ef">width</span>: <span style="color:#ae81ff">80px</span>;
  <span style="color:#66d9ef">height</span>: <span style="color:#ae81ff">80px</span>;
}
<span style="color:#a6e22e">.lds_ellipsis</span> <span style="color:#f92672">div</span> {
  <span style="color:#66d9ef">position</span>: absolute;
  <span style="color:#66d9ef">top</span>: <span style="color:#ae81ff">33px</span>;
  <span style="color:#66d9ef">width</span>: <span style="color:#ae81ff">15px</span>;
  <span style="color:#66d9ef">height</span>: <span style="color:#ae81ff">15px</span>;
  <span style="color:#66d9ef">border-radius</span>: <span style="color:#ae81ff">50%</span>;
  <span style="color:#66d9ef">background</span>: <span style="color:#e6db74">var</span>(--orange);
  <span style="color:#66d9ef">animation-timing-function</span>: <span style="color:#e6db74">cubic-bezier</span>(0, 1, 1, 0);
}
<span style="color:#a6e22e">.lds_ellipsis</span> <span style="color:#f92672">div</span><span style="color:#e6db74">:nth-child</span><span style="color:#e6db74">(</span><span style="color:#e6db74">1</span><span style="color:#e6db74">)</span> {
  <span style="color:#66d9ef">left</span>: <span style="color:#ae81ff">8px</span>;
  <span style="color:#66d9ef">animation</span>: lds_ellipsis1 <span style="color:#ae81ff">0.6s</span> infinite;
}
<span style="color:#a6e22e">.lds_ellipsis</span> <span style="color:#f92672">div</span><span style="color:#e6db74">:nth-child</span><span style="color:#e6db74">(</span><span style="color:#e6db74">2</span><span style="color:#e6db74">)</span> {
  <span style="color:#66d9ef">left</span>: <span style="color:#ae81ff">8px</span>;
  <span style="color:#66d9ef">animation</span>: lds_ellipsis2 <span style="color:#ae81ff">0.6s</span> infinite;
}
<span style="color:#a6e22e">.lds_ellipsis</span> <span style="color:#f92672">div</span><span style="color:#e6db74">:nth-child</span><span style="color:#e6db74">(</span><span style="color:#e6db74">3</span><span style="color:#e6db74">)</span> {
  <span style="color:#66d9ef">left</span>: <span style="color:#ae81ff">32px</span>;
  <span style="color:#66d9ef">animation</span>: lds_ellipsis2 <span style="color:#ae81ff">0.6s</span> infinite;
}
<span style="color:#a6e22e">.lds_ellipsis</span> <span style="color:#f92672">div</span><span style="color:#e6db74">:nth-child</span><span style="color:#e6db74">(</span><span style="color:#e6db74">4</span><span style="color:#e6db74">)</span> {
  <span style="color:#66d9ef">left</span>: <span style="color:#ae81ff">56px</span>;
  <span style="color:#66d9ef">animation</span>: lds_ellipsis3 <span style="color:#ae81ff">0.6s</span> infinite;
}
@<span style="color:#f92672">keyframes</span> lds_ellipsis1 {
  0% {
    <span style="color:#66d9ef">transform</span>: <span style="color:#e6db74">scale</span>(0);
  }
  100% {
    <span style="color:#66d9ef">transform</span>: <span style="color:#e6db74">scale</span>(1);
  }
}
@<span style="color:#f92672">keyframes</span> lds_ellipsis3 {
  0% {
    <span style="color:#66d9ef">transform</span>: <span style="color:#e6db74">scale</span>(1);
  }
  100% {
    <span style="color:#66d9ef">transform</span>: <span style="color:#e6db74">scale</span>(0);
  }
}
@<span style="color:#f92672">keyframes</span> lds_ellipsis2 {
  0% {
    <span style="color:#66d9ef">transform</span>: <span style="color:#e6db74">translate</span>(0, 0);
  }
  100% {
    <span style="color:#66d9ef">transform</span>: <span style="color:#e6db74">translate</span>(24px, 0);
  }
}</code></span></span></span></span>

因此,您已经成功地使用自定义样式构建了加载屏幕组件,现在是时候在每次路由更改时在 Web 应用程序上呈现它了。

为此,我们将借助 Next.js 路由器事件,您可以侦听 Next.js 路由器内部发生的不同事件。

以下是支持的事件列表:

<span style="color:#333333"><span style="background-color:#ffffff"><span style="background-color:#201e2f"><span style="color:#f8f8f2"><code>routeChangeStart(url, { shallow }) - Fires when a route starts to change

routeChangeComplete(url, { shallow }) - Fires when a route changed completely

routeChangeError(err, url, { shallow }) - Fires when there<span style="color:#e6db74">'s an error when changing routes, or a route load is cancelled</span>
<span style="color:#e6db74">
err.cancelled - Indicates if the navigation was cancelled</span>
<span style="color:#e6db74">
beforeHistoryChange(url, { shallow }) - Fires before changing the browser'</span>s history

hashChangeStart(url, { shallow }) - Fires when the hash will change but not the page

hashChangeComplete(url, { shallow }) - Fires when the hash has changed but not the page</code></span></span></span></span>

有关这些事件和其他路由器方法的更多详细信息,您可以访问Next.js 官方文档

借助这些事件,您可以将加载屏幕组件添加到 app.js 中,看看如何:

首先导入{useState, useEffect}from "react"{useRouter}from"next/router"和您的Loading组件。

<span style="color:#333333"><span style="background-color:#ffffff"><span style="background-color:#201e2f"><span style="color:#f8f8f2"><code><span style="color:#f92672">import</span> { useState, useEffect } <span style="color:#f92672">from</span> <span style="color:#e6db74">"</span><span style="color:#e6db74">react</span><span style="color:#e6db74">"</span>;
<span style="color:#f92672">import</span> { useRouter } <span style="color:#f92672">from</span> <span style="color:#e6db74">"</span><span style="color:#e6db74">next/router</span><span style="color:#e6db74">"</span>;
<span style="color:#f92672">import</span> Loading <span style="color:#f92672">from</span> <span style="color:#e6db74">"</span><span style="color:#e6db74">../components/Loading</span><span style="color:#e6db74">"</span>;</code></span></span></span></span>

现在我们将loading使用useState钩子声明变量并使用它进行初始化false,我们将true在路由更改时将其设置为,并在路由更改完成后将其恢复为 false。

我们将把这个逻辑放在useEffecthook 中并设置router为它的依赖项。这意味着每次router更改useEffect钩子内的逻辑都会被执行。

<span style="color:#333333"><span style="background-color:#ffffff"><span style="background-color:#201e2f"><span style="color:#f8f8f2"><code><span style="color:#f92672">function</span> <span style="color:#a6e22e">MyApp</span>(<span style="color:#f8f8f2">{</span> <span style="color:#f8f8f2">Component</span><span style="color:#f8f8f2">,</span> <span style="color:#f8f8f2">pageProps</span> <span style="color:#f8f8f2">}</span>) {
<span style="color:#f92672">const</span> router = useRouter();
<span style="color:#f92672">const</span> [loading, setLoading] = useState(<span style="color:#ae81ff">false</span>);

useEffect(() => {
    <span style="color:#f92672">const</span> handleStart = (url) => {
      url !== router.pathname ? setLoading(<span style="color:#ae81ff">true</span>) : setLoading(<span style="color:#ae81ff">false</span>);
    };
    <span style="color:#f92672">const</span> handleComplete = (url) => setLoading(<span style="color:#ae81ff">false</span>);

    router.events.on(<span style="color:#e6db74">"</span><span style="color:#e6db74">routeChangeStart</span><span style="color:#e6db74">"</span>, handleStart);
    router.events.on(<span style="color:#e6db74">"</span><span style="color:#e6db74">routeChangeComplete</span><span style="color:#e6db74">"</span>, handleComplete);
    router.events.on(<span style="color:#e6db74">"</span><span style="color:#e6db74">routeChangeError</span><span style="color:#e6db74">"</span>, handleComplete);
  }, [router]);

  <span style="color:#f92672">return</span> (
    <>
          <Loading loading={loading} />  
          <Component {...pageProps} />
    </>
  );
}

export default MyApp;
}</code></span></span></span></span>

我们将通过loading变量为道具,以我们的Loading组件,以便随时loadingtrue Loading组件将已经classdisplay: block当它是false将有classdisplay: none

结论

这是在 Next.js 中制作自定义加载屏幕的方法。我希望这个博客可以帮助您并节省您的时间和精力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_45378258

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值