一篇让小白也能看懂的 Next.js 路由字典
“原来文件名就是网址!”——看完这一篇,你就再也不会写错路由。
📌 先记住一句话
在 Next.js App Router 里:
文件夹名 = 网址段,文件名 = 特殊功能,方括号 = 参数,双层方括号 = 可省略参数。
🗂️ 目录总览
| 场景 | 关键词 | 举例网址 | 对应文件 |
|---|---|---|---|
| 普通页面 | 固定名字 | /about |
app/about/page.js |
| 带参数页 | 单参数 [id] |
/user/123 |
app/user/[id]/page.js |
| 任意多级参数 | 全捕获 [...slug] |
/docs/a/b/c |
app/docs/[...slug]/page.js |
| 可省参数 | 可选捕获 [[...slug]] |
/shop 或 /shop/123 |
app/shop/[[...slug]]/page.js |
| 分组但不显示 | 括号 (group) |
同父级 | app/(group)/xxx/page.js |
| 全局布局 | layout.js |
当前目录 + 所有子目录 | app/layout.js |
| 全局错误 | error.js |
当前目录 + 子目录出错时 | app/error.js |
| API 接口 | route.js |
/api/hello |
app/api/hello/route.js |
| 中间件 | middleware.js |
所有请求 | 根目录 middleware.js |
🎯 1️⃣ 普通页面(固定名字)
文件名就是网址,啥括号也没有。
app
└─ about
└─ page.js → 网址 /about
- 浏览器访问
http://localhost:3000/about就能看到about/page.js渲染的内容。 - 多级同理:
app/blog/2023/page.js→/blog/2023
🎯 2️⃣ 单参数 [id](一个坑位)
写 [id] 就能拿到网址里的任何一段。
app
└─ user
└─ [id]
└─ page.js
| 网址 | 参数值 |
|---|---|
/user/123 |
params.id = "123" |
/user/abc |
params.id = "abc" |
代码示例:
tsx
export default function UserPage({ params }) {
return <h1>用户 ID: {params.id}</h1>;
}
🎯 3️⃣ 全捕获 [...slug](无限段)
所有斜杠后面的内容一次性给你。
app
└─ docs
└─ [...slug]
└─ page.js
| 网址 | 参数值 |
|---|---|
/docs |
params.slug = [] |
/docs/a/b/c/d |
params.slug = ["a","b","c","d"] |
🎯 4️⃣ 可选捕获 [[...slug]](可省)
后面整段都能不要。
app
└─ shop
└─ [[...slug]]
└─ page.js
| 网址 | 参数值 |
|---|---|
/shop |
params.slug = undefined |
/shop/123 |
params.slug = ["123"] |
🎯 5️⃣ 路由分组 (group):文件夹名不出现在网址里
app
├─ (marketing) ← 括号里的名字 **不会** 出现在网址
│ └─ about
│ └─ page.js → 网址仍是 /about
└─ (shop)
└─ checkout
└─ page.js → 网址 /checkout
作用:
- 多团队并行开发(marketing 组、shop 组互不干扰)。
- 共享同一套 layout,但 URL 保持简洁。
🎯 6️⃣ layout.js 与 page.js 的区别
| 文件 | 作用 | 示例 |
|---|---|---|
page.js |
显示内容 | app/about/page.js 渲染页面 |
layout.js |
外壳框架(HTML、头、尾、导航) | app/layout.js 给所有页面加统一 <header> |
🎯 7️⃣ API 路由 route.js:不写页面,写接口
app
└─ api
└─ hello
└─ route.js
访问 http://localhost:3000/api/hello 即可:
ts
// route.js
export async function GET(request) {
return Response.json({ msg: 'Hello API!' });
}
🎯 8️⃣ 中间件 middleware.js:请求进来先过安检
app
└─ middleware.js
ts
import { NextResponse } from 'next/server';
export function middleware(req) {
const token = req.cookies.get('auth')?.value;
if (!token) {
return NextResponse.redirect(new URL('/login', req.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/dashboard/:path*'], // 只拦截 /dashboard 下
};
🎯 9️⃣ 优先级(谁会被先匹配)
- 精确匹配
/about - 单参数
/user/[id] - 全捕获
/docs/[...slug] - 可选捕获
/shop/[[...slug]]
✅ 10 秒速查清单
| 需求 | 文件名 |
|---|---|
| 普通页面 | xxx/page.js |
| 单参数 | [id]/page.js |
| 任意多级 | [...slug]/page.js |
| 可省参数 | [[...slug]]/page.js |
| 分组隐藏 | (group)/xxx/page.js |
| 全局布局 | layout.js |
| 全局错误 | error.js |
| API 接口 | route.js |
| 中间件 | middleware.js |
🎉 一句话总结
文件夹名就是网址,方括号是参数,双层括号可省,文件名决定功能。
背下这张表,再写 Next.js 路由再也不会晕!
![[Next.js篇]一篇让小白也能看懂的 Next.js 路由字典](/_next/image?url=https%3A%2F%2Fwww.baozangtuku.com%2Fd%2Ffile%2Fp%2F20250710%2Fsmall9ea3be855abdb774d430e66852ab429b.jpg&w=3840&q=75)