Next.js 搭建项目框架与导航,了解 App 路由定义、跳转、布局与特殊页面

搭建项目,实现了基础框架和头部导航,记录其中涉及的路由定义、路由状态与跳转、布局、特殊页面、Metadata 文件等知识点。公共布局、导航、404页面等代码使用 Ant Design 作为示例。

路由定义

路由入口文件

路由入口文件,page.tsx ,里面就是这个路由默认渲染的内容。有点类似于 index.html 的效果。

特殊文件约定

https://nextjs.org/docs/app/api-reference/file-conventions

纯组件目录

https://nextjs.org/docs/app/building-your-application/routing/colocation#project-organization-features

在 app 目录中, 以 _ 下划线开头的目录不会作为路由页面使用,可用于放组件。

路由组

https://nextjs.org/docs/app/building-your-application/routing/colocation#route-groups

可以通过将文件夹括在括号中来创建路由组: (folderName) ,这表示该文件夹用于组织目的,不应包含在路由的 URL 路径中。如:

  • (test)/page.tsx 页面,访问路径为 /
  • (test)/something/page.tsx 页面,访问路径为 /something

动态路由

https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes

动态路由,可通过目录路径中的 [id] 表示参数。

获取参数:

const IdPage = ({params}: {params: {id:string}}) => {
    return <div>ID page: {params.id}</div>
}
  • [...slug] 路径表示将 url 后面的每一段都读取,作为数组
  • [[...slug]] 表示后续的路由段可为空

路由状态与跳转

usePathname 获取当前路由

通过 usePathname 可获取当前路径,用于判断导航当前激活状态。

import { usePathname } from 'next/navigation';

const items = [
    {
        key: '/',
        label: '首页',
    },
    {
        key: '/about',
        label: '关于',
    }
]

const Nav = () => {
    const pathName = usePathname();

    return <Menu
        theme="light"
        mode="horizontal"
        defaultSelectedKeys={[pathName]}
        items={items}
        style={{
            flex: 1,
            minWidth: 0,
            borderBottom: 'unset',
            justifyContent: 'flex-end'
        }}
    />
}

Link 路由跳转

<Link href="/" style={{
  width: '153px',
  height: '38px',
  marginRight: '20px'
}}>
  <Image src="/logo.svg" width={153} height={38} alt="logo" />
</Link>

默认启用预加载,可设置 prefetch 为 false 来禁止。

<Link href="/" prefetch={false}></Link>

useRouter 跳转

import { useRouter } from 'next/navigation';

const router = useRouter();
const onClick: MenuProps['onClick'] = e => {
    router.push(e.key);
}

useSearchParams 获取请求参数

获取:

const searchParams = useSearchParams();
const v = searchParams.get('v');

在客户端组件使用时需要被 Suspense 组件包裹,可通过 fallback 设置 loading 或骨架屏。

searchParams 没有 set 方法,通过 useRouter 或 Link 改变路由实现改变 searchParams 。

布局与特殊页面

公共布局文件

https://nextjs.org/docs/app/api-reference/file-conventions/layout

layout.tsx 可用于编写公共布局文件,生效于所有子目录的文件。

也可以在这里设置 Ant Design 的全局样式和配置。

使用单独的 CommonLayout 客户端组件去引入 Ant Design 组件。

import { AntdRegistry } from '@ant-design/nextjs-registry';
import { ConfigProvider } from "antd";
import type { Metadata } from "next";
import CommonLayout from "./_components/CommonLayout";
import "./globals.css";

export const metadata: Metadata = {
  title: "Next.js Fullstack Demo",
  description: "Generated by heibaimeng",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="zh">
      <body>
        <AntdRegistry>
          <ConfigProvider
            theme={{
              token: {
                colorPrimary: '#003366',
              },
              components: {
                Layout: {
                  headerBg: '#fff'
                },
              },
            }}
          >
            <CommonLayout>
              {children}
            </CommonLayout>
          </ConfigProvider>
        </AntdRegistry>
      </body>
    </html>
  );
}

not-found

https://nextjs.org/docs/app/api-reference/file-conventions/not-found

import Link from "next/link"
import { Button, Result } from 'antd';

const NotFound = () => (
  <Result
    status="404"
    title="404"
    subTitle="抱歉,您访问的页面不存在。"
    extra={<Link href="/"><Button type="primary">回到首页</Button></Link>}
  />
);

export default NotFound;

error

https://nextjs.org/docs/app/api-reference/file-conventions/error

在服务端组件中抛出 Error ,可看到效果。

"use client"

import Link from "next/link"
import { Button, Result } from 'antd';

const Error = () => (
  <Result
  status="500"
  title="500"
  subTitle="抱歉,页面出现错误。"
    extra={<Link href="/"><Button type="primary">回到首页</Button></Link>}
  />
);

export default Error;

loading

https://nextjs.org/docs/app/api-reference/file-conventions/loading

打开控制台切换到 slow 3g ,再切换路由,可看到效果。

import { Spin } from 'antd';

const Loading = () => {
  return (
    <div style={{
      width: '100%',
      height: '150px',
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center'
    }}>
      <Spin size="large" />
    </div>
  )
}

export default Loading

Metadata 文件

配置 metadate

https://nextjs.org/docs/app/building-your-application/optimizing/metadata

可以直接 export 一个对象来设置,配置标题、描述、网站 icon,比以前方便不少。

export const metadata: Metadata = {
  title: "Next.js Fullstack Demo",
  description: "Generated by heibaimeng",
};

可在公共布局文件中设置公共的 metadata ,并可以在页面路由组件内单独设置来覆盖它。

sitemap

https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap

在 app 目录下创建 sitemap.ts 可动态创建 sitemap.xml 文件。如:

import { MetadataRoute } from 'next'
 
export default function sitemap(): MetadataRoute.Sitemap {
  return [
    {
      url: 'https://heibaimeng.com',
      lastModified: new Date(),
      changeFrequency: 'weekly',
      priority: 1,
    },
    {
      url: 'https://heibaimeng.com/collections/1',
      lastModified: new Date(),
      changeFrequency: 'monthly',
      priority: 0.8,
    },
  ]
}

其他文件

本文收录于专栏
使用 Next.js 搭建 SSR 全栈 demo ,以及构建 SSG 纯静态博客,记录学习和使用笔记