【Next.js】路由跳转显示进度条

本期已录制 B 站视频 👉 【Next.js】路由跳转显示进度条

哈喽,我是楷鹏。

先来看一个反面教材。

Dify.ai 中,当点击跳转页面之后,会有一段需要等待的时间,然后才会跳转页面。

然而,中间这段时间我并不知道是否跳转成功了,所以我会多点了几下,直到跳转。

这种体验很不好 👎

解决方案很简单,我们来看一下 GitHub 的跳转交互。

可以看到,GitHub 在跳转期间,会显示一个进度条,清晰地告诉用户------"我正在跳转,请稍等"。

那么在 Next.js 中,如何实现这个效果呢?

我们可以借助 BProgress 这个库来实现。

BProgress 是一个轻量级的进度条组件库,支持 Next.js 15+,同时也支持 Remix、Vue 等其他框架。

对于 BProgress 的使用,我做了一个 demo 项目 nextjs-progress-bar-demo,我们可以把这个项目先 clone 下来:

bash 复制代码
git clone [email protected]:wukaipeng-dev/nextjs-progress-bar-demo.git

然后进入项目目录:

bash 复制代码
cd nextjs-progress-bar-demo

先安装依赖:

bash 复制代码
npm install @bprogress/next

启动项目:

bash 复制代码
npm run dev

可以看到,这是一个简单的 Next.js 项目,包含三个页面:首页、登录页、注册页。

main 分支已经配置好了进度条,我们切换到分支 without-progress-bar-demo

bash 复制代码
git checkout without-progress-bar-demo

当前分支下,我们没有配置进度条,所以跳转页面时,不会显示进度条。

接下来我们在根布局 app/layout.tsx 中引入 ProgressProvider

tsx 复制代码
'use client';

import "./globals.css";
import { ProgressProvider } from '@bprogress/next/app';

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body>
        <ProgressProvider
          height="4px"
          color="#4c3aed"
          options={{ showSpinner: false }}
          shallowRouting
          >
          {children}
        </ProgressProvider>
      </body>
    </html>
  );
}

接下来,我们可以看一下,在首页和登录页、登录页和注册页之间跳转,都会显示一个进度条。

ProgressProvider 的参数如下:

  • height:进度条的高度
  • color:进度条的颜色
  • options:进度条的配置,这里 showSpinner 设置为 false,表示不显示一个动画的加载图标。
  • shallowRouting:是否启用浅层路由,如果开启的话,只改变路由的 query 参数,比如 ?page=1 变成 ?page=2,那么进度条不会重新加载。

但是,当我们登录成功之后,再点击跳转,却不会显示进度条。

这是因为,首页和登录页、登录页和注册页之间,是使用 <Link> 组件进行跳转的。

<Link> 组件实际会渲染成 <a>,BProgress 通过给所有 <a> 组件添加点击事件,来显示进度条。

我们可以看下在 DevTools → Elements → <a> → Event Listeners 中,是否添加了点击事件:

但是,当我们登录成功之后,则是使用 router.push 进行跳转的。

BProgress 不会给 router.push 添加点击事件,自然也不会显示进度条。

不用慌,BProgress 为我们提供了 useRouter 方法。

将 Next.js 的 useRouter 替换为 BProgress 提供的 useRouter

tsx 复制代码
// import { useRouter } from 'next/navigation';
import { useRouter } from '@bprogress/next/app';

然后,正常使用即可:

tsx 复制代码
const router = useRouter();

router.push('/');

这时,你可以看到,在登录成功之后,自动跳转首页时,进度条就能正常显示了。

但如果你的项目已经封装过了自己的 useRouter,那么你可以将封装过的 useRouter 作为参数 customRouter 传入,进行二次封装:

tsx 复制代码
import { useRouter } from '@bprogress/next/app';
import { useRouter as useNextIntlRouter } from '@/i18n/navigation';

export default function Home() {
  const router = useRouter({
    customRouter: useNextIntlRouter,
  });

  return (
    <button
      onClick={() =>
        router.push('/about', {
          startPosition: 0.3,
          locale: 'en',
        })
      }
    >
      Go to about page
    </button>
  );
}

最后,让我们回到 app/layout.tsx,这里我们引入了 ProgressProvider,但却把 app/layout 变成了一个客户端组件,我们来把 ProgressProvider 抽离到其他地方,仍然保持 app/layout 是一个服务端组件。

tsx 复制代码
// app/components/ProgressWrapper.tsx
'use client';

import { ProgressProvider } from '@bprogress/next/app';

interface ProgressWrapperProps {
  children: React.ReactNode;
}

export function ProgressWrapper({ children }: ProgressWrapperProps) {
  return (
    <ProgressProvider
      height="4px"
      color="#0000ff"
      options={{ showSpinner: false }}
      shallowRouting
    >
      {children}
    </ProgressProvider>
  );
}

app/layout.tsx 中,我们引入 ProgressWrapper

tsx 复制代码
import { ProgressWrapper } from './components/ProgressWrapper';

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body>
        <ProgressWrapper>
          {children}
        </ProgressWrapper>
      </body>
    </html>
  );
}

好的,不愧是你,完成了一个 Next.js 集成路由跳转显式进度条的封装。

以上就是本期的全部内容,希望对你有所帮助。

感谢观看!👏

相关推荐
番茄比较犟4 分钟前
GlobalKey 第一篇
前端
Sun_light6 分钟前
AJAX揭秘 网页局部刷新其实很简单
前端·javascript
teeeeeeemo1 小时前
Number.toFixed() 与 Math.round() 深度对比解析
开发语言·前端·javascript·笔记
驳是1 小时前
入坑 Docusaurus,看这一篇就够了
react.js·前端框架·markdown
阿珊和她的猫2 小时前
`toRaw` 与 `markRaw`:Vue3 响应式系统的细粒度控制
前端·javascript·vue.js·typescript
网络点点滴2 小时前
探索 Vue 替代方案
前端·javascript·vue.js
江城开朗的豌豆2 小时前
Vue的keep-alive缓存揭秘:多出来的生命周期怎么玩?
前端·javascript·vue.js
BoredWait2 小时前
vite+vue-ts 如何在项目中实现多语言
前端·javascript
年纪轻轻就扛不住2 小时前
keep-alive实现原理及Vue2/Vue3对比分析
前端·javascript·vue.js
这是个栗子2 小时前
黑马头条-数据管理平台
前端·javascript·ajax