Next.js 中的文件路由和路由组。这是 Next.js App Router(基于 React Server Components 的路由系统)的核心概念。 App Router (app 目录),这是 Next.js 13.4+ 版本中推荐的、更强大的路由系统,而不是旧的 Pages Router(pages 目录)。
一、文件路由基础
在 App Router 中,文件系统就是路由 API 。你不需要手动配置路由文件,只需在 app 目录下创建特定的文件和文件夹,Next.js 会自动为你创建路由。
1. 核心文件
| 文件名 | 作用 |
|---|---|
page.tsx |
路由的UI界面。定义了特定路径下用户看到的内容。 |
layout.tsx |
共享的UI布局。定义了该路由及其所有子路由的共享UI(如导航栏、页脚)。 |
loading.tsx |
加载中的UI 。在 page.tsx 或其 children 的数据加载时,会立即显示此组件,实现 instant UI。 |
error.tsx |
错误边界UI。当路由段中发生错误时,会自动替换并显示此组件。 |
not-found.tsx |
404页面UI。当路由未找到时,会显示此组件。 |
2. 基本路由规则
a. 根路由 (/)
- 文件路径:
app/page.tsx - 访问URL:
http://localhost:3000/
tsx
// app/page.tsx
export default function HomePage() {
return <h1>欢迎来到首页!</h1>;
}
b. 嵌套路由
- 文件夹结构:
app/dashboard/settings/page.tsx - 访问URL:
http://localhost:3000/dashboard/settings每个文件夹代表一个路由段。
arduino
app/
└── dashboard/
└── settings/
└── page.tsx // 对应 /dashboard/settings
c. 动态路由
- 用于处理像
/blog/1,/blog/2这样的动态内容页面。 - 文件夹名用方括号包裹:
[folderName]。 - 文件路径:
app/blog/[slug]/page.tsx - 访问URL:
http://localhost:3000/blog/hello-world你可以在组件中通过params获取动态参数。
tsx
// app/blog/[slug]/page.tsx
export default function BlogPostPage({ params }: { params: { slug: string } }) {
return <h1>博客文章: {params.slug}</h1>;
}
d. 捕获所有路由
- 用于处理多层嵌套的动态路由,如
/docs/v1/getting-started/install。 - 文件夹名用省略号包裹:
[...folderName]。 - 文件路径:
app/docs/[...slug]/page.tsx - 访问URL:
http://localhost:3000/docs/v1/getting-startedparams.slug会是一个数组['v1', 'getting-started']。 e. 平行路由 - 在同一个布局中同时渲染一个或多个页面。非常适合用于复杂的仪表盘(如带侧边栏和主内容区)。
- 文件夹名用
@符号作为前缀:@folderName。 - 文件结构:
java
app/
├── layout.tsx
├── @analytics/
│ └── page.tsx // 分析页面
└── @team/
└── page.tsx // 团队页面
layout.tsx中需要使用childrenprop 来接收和渲染这些平行路由。
tsx
// app/layout.tsx
export default function DashboardLayout({
children, // 主路由,如 /dashboard
analytics, // @analytics 路由
team, // @team 路由
}: {
children: React.ReactNode;
analytics: React.ReactNode;
team: React.ReactNode;
}) {
return (
<section>
{/* 导航栏 */}
<nav>...</nav>
<div className="flex">
<div className="flex-1">{children}</div>
<aside className="w-64">
{analytics}
{team}
</aside>
</div>
</section>
);
}
二、路由组
这是理解 Next.js App Router 布局的关键。
1. 为什么需要路由组?
想象一个场景:你有一个 app 目录,里面有 /dashboard 和 /marketing 两个部分。你希望它们有不同的布局。
arduino
app/
├── dashboard/
│ ├── layout.tsx // 仪表盘布局
│ └── page.tsx
└── marketing/
├── layout.tsx // 市场营销布局
└── page.tsx
这看起来没问题。但如果 /dashboard 和 /marketing 下面都有一个共同的子页面,比如 /settings 呢?
arduino
app/
├── dashboard/
│ ├── layout.tsx
│ ├── page.tsx
│ └── settings/
│ └── page.tsx // 应该用仪表盘布局
└── marketing/
├── layout.tsx
├── page.tsx
└── settings/
└── page.tsx // 应该用市场营销布局
这会导致 URL 变成 /dashboard/settings 和 /marketing/settings。但我们可能希望 URL 就是 /settings,并且根据上下文(比如从哪个入口进入)来决定使用哪个布局。 路由组就是为了解决这个问题:在不影响 URL 路径的情况下,对路由进行逻辑分组,从而共享布局。
2. 如何使用路由组?
- 创建一个文件夹,名称用圆括号包裹:
(folderName)。 (folderName)本身不会成为 URL 路径的一部分。 让我们用路由组来重构上面的例子:
bash
app/
├── (dashboard)/ # 这是一个路由组,不影响URL
│ ├── layout.tsx # 这个布局会应用到组内所有页面
│ ├── page.tsx # URL: /
│ └── settings/
│ └── page.tsx # URL: /settings
│
└── (marketing)/ # 另一个路由组
├── layout.tsx # 另一个独立的布局
└── login/
└── page.tsx # URL: /login
发生了什么?
- URL 路径 :
app/(dashboard)/page.tsx-> URL 是/(因为(dashboard)被忽略了)。app/(dashboard)/settings/page.tsx-> URL 是/settings。app/(marketing)/login/page.tsx-> URL 是/login。
- 布局 :
- 访问
/或/settings时,会使用app/(dashboard)/layout.tsx。 - 访问
/login时,会使用app/(marketing)/layout.tsx。
- 访问
3. 路由组的核心用途
a. 按功能或布局组织代码 你可以将相关的页面放在一个路由组里,即使它们的 URL 没有共同的前缀。这让项目结构更清晰。 b. 在同一路径下选择性地应用布局 假设你的网站大部分页面使用一个主布局,但登录和注册页面不需要(它们是全屏的)。
bash
app/
├── layout.tsx # 网站主布局(带header, footer)
├── page.tsx # 首页 / -> 使用主布局
├── about/
│ └── page.tsx # /about -> 使用主布局
│
└── (auth)/ # 认证相关路由组
├── layout.tsx # 认证布局(可能很简单,只有一个居中的容器)
├── login/
│ └── page.tsx # /login -> 使用认证布局,不使用主布局
└── register/
└── page.tsx # /register -> 使用认证布局,不使用主布局
当用户访问 /login 时,Next.js 会查找最近的 layout.tsx。它首先在 app/(auth)/ 下找到了一个,所以会使用这个布局,而不会 向上冒泡到 app/layout.tsx。
总结与对比
| 概念 | 语法 | 是否影响URL | 主要用途 |
|---|---|---|---|
| 文件路由 | 创建文件夹和page.tsx |
是 | 定义网站的实际URL结构和页面内容。 |
| 动态路由 | [slug] |
是 | 处理博客文章、用户资料等动态内容页。 |
| 平行路由 | @analytics |
否 (作为插槽名) | 在同一视图中同时渲染多个独立的页面。 |
| 路由组 | (dashboard) |
否 | 在不改变URL的前提下,对路由进行逻辑分组,以便共享布局或组织代码。 |
| 关键要点: |
page.tsx决定了 "是什么"(页面内容)。layout.tsx决定了 "怎么包"(页面框架)。- 文件夹结构 决定了 "在哪里"(URL路径)。
(路由组)是一个 "虚拟文件夹" ,它帮助你在 "在哪里" 这个问题上做文章,让你可以更灵活地组织layout.tsx,而不会污染实际的 URL。 理解了文件路由和路由组,你就掌握了 Next.js App Router 的精髓,可以构建出结构清晰、可维护性高的复杂 Web 应用了。