页面间导航

在上一章节中,您已创建仪表板布局和页面。现在,让我们添加一些链接以便用户在仪表板路由间导航。

为何需要优化导航?

传统上,页面间链接会使用 <a> HTML 元素。当前侧边栏链接使用了 <a> 元素,但请注意在浏览器中导航至首页、发票和客户页面时会发生什么。

您发现了吗?

每次页面导航都会触发整页刷新!

在 Next.js 中,您可以使用 <Link /> 组件实现应用内的页面间链接。<Link> 支持通过 JavaScript 进行客户端导航

要使用 <Link /> 组件,请打开 /app/ui/dashboard/nav-links.tsx,并从 next/link 导入 Link 组件。然后将 <a> 标签替换为 <Link>

/app/ui/dashboard/nav-links.tsx
import {
  UserGroupIcon,
  HomeIcon,
  DocumentDuplicateIcon,
} from '@heroicons/react/24/outline';
import Link from 'next/link';
 
// ...
 
export default function NavLinks() {
  return (
    <>
      {links.map((link) => {
        const LinkIcon = link.icon;
        return (
          <Link
            key={link.name}
            href={link.href}
            className="flex h-[48px] grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3"
          >
            <LinkIcon className="w-6" />
            <p className="hidden md:block">{link.name}</p>
          </Link>
        );
      })}
    </>
  );
}

如您所见,Link 组件的使用方式与 <a> 标签类似,但使用 <Link href="…"> 替代了 <a href="…">

保存更改并在本地环境中查看效果。现在您应该能在页面间导航而不会看到整页刷新。虽然应用的部分内容在服务端渲染,但没有整页刷新,使其体验更像原生网页应用。这是为什么?

自动代码分割与预加载

为了提升导航体验,Next.js 会按路由段自动进行代码分割。这与传统的 React 单页应用 (SPA) 不同,后者会在初始页面加载时加载全部应用代码。

按路由分割代码意味着各页面相互隔离。如果某个页面出错,其他页面仍能正常工作。同时浏览器需要解析的代码量更少,从而提升应用性能。

此外,在生产环境中,当 <Link> 组件出现在浏览器视口时,Next.js 会自动在后台预加载目标路由的代码。当用户点击链接时,目标页面的代码已在后台加载完成,这使得页面切换几乎瞬间完成!

了解更多关于导航工作原理

模式:显示当前活动链接

常见的 UI 模式是通过高亮显示当前页面链接。要实现这一点,您需要从 URL 获取用户的当前路径。Next.js 提供了 usePathname() 钩子来检查路径并实现此模式。

由于 usePathname() 是 React 钩子,您需要将 nav-links.tsx 转换为客户端组件。在文件顶部添加 React 的 "use client" 指令,然后从 next/navigation 导入 usePathname()

/app/ui/dashboard/nav-links.tsx
'use client';
 
import {
  UserGroupIcon,
  HomeIcon,
  DocumentDuplicateIcon,
} from '@heroicons/react/24/outline';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
 
// ...

接着,在 <NavLinks /> 组件内将路径赋值给 pathname 变量:

/app/ui/dashboard/nav-links.tsx
export default function NavLinks() {
  const pathname = usePathname();
  // ...
}

注意nav-links.tsx 并非 Next.js 的特殊文件——您可以自由命名。如果重命名,请确保更新相关导入语句。

您可以使用 CSS 样式 章节介绍的 clsx 库,在链接激活时条件式应用类名。当 link.href 匹配 pathname 时,链接会显示为蓝色文字和浅蓝色背景。

以下是 nav-links.tsx 的最终代码:

/app/ui/dashboard/nav-links.tsx
'use client';
 
import {
  UserGroupIcon,
  HomeIcon,
  DocumentDuplicateIcon,
} from '@heroicons/react/24/outline';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import clsx from 'clsx';
 
// ...
 
export default function NavLinks() {
  const pathname = usePathname();
 
  return (
    <>
      {links.map((link) => {
        const LinkIcon = link.icon;
        return (
          <Link
            key={link.name}
            href={link.href}
            className={clsx(
              'flex h-[48px] grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3',
              {
                'bg-sky-100 text-blue-600': pathname === link.href,
              },
            )}
          >
            <LinkIcon className="w-6" />
            <p className="hidden md:block">{link.name}</p>
          </Link>
        );
      })}
    </>
  );
}

保存并在本地环境中查看效果。现在您应该能看到当前活动链接显示为蓝色高亮。

On this page