Appearance
第4章:路由系统(Next.js 核心优势,无需手动配置)
4.1 App Router 核心概念(Next.js 14 重点,推荐学习)
App Router 是 Next.js 13+ 引入的新路由系统,基于文件夹结构定义路由,提供了更现代化的路由体验。
约定式路由(app 目录下文件/文件夹自动生成路由)
App Router 使用文件系统的约定来定义路由,具体规则如下:
- 文件夹:对应 URL 路径
- page.js:对应页面组件,是路由的终点
- layout.js:对应布局组件,应用于当前目录及其子目录
- loading.js:对应加载状态组件
- error.js:对应错误边界组件
- not-found.js:对应 404 页面组件
路由示例:
| 文件夹结构 | 对应的 URL 路径 |
|---|---|
app/page.js | / |
app/about/page.js | /about |
app/blog/page.js | /blog |
app/blog/[id]/page.js | /blog/1 |
页面组件(page.js)与布局组件(layout.js)的区别与使用
页面组件(page.js)
- 作用:定义页面内容,是路由的终点
- 特点:每个路由必须有一个
page.js文件 - 示例:
jsx
// app/page.js
import Link from 'next/link';
export default function Home() {
return (
<div>
<h1>Home Page</h1>
<p>Welcome to my Next.js app!</p>
<Link href="/about">About</Link>
</div>
);
}布局组件(layout.js)
- 作用:定义共享布局,应用于当前目录及其子目录
- 特点:可选,默认继承父级布局
- 示例:
jsx
// app/layout.js
import './globals.css';
export const metadata = {
title: 'My Next.js App',
description: 'A Next.js app with App Router',
};
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<header>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/blog">Blog</a></li>
</ul>
</nav>
</header>
<main>{children}</main>
<footer>
<p>© 2024 My Next.js App</p>
</footer>
</body>
</html>
);
}路由分组((group) 语法,不影响路由路径,用于逻辑分组)
路由分组允许你将路由按逻辑分组,而不影响 URL 路径。使用括号 (group) 包裹文件夹名称。
示例:
app/
├── (auth)/
│ ├── login/page.js # /login
│ └── register/page.js # /register
├── (dashboard)/
│ ├── layout.js
│ ├── page.js # /
│ └── settings/page.js # /settings
└── layout.js # 根布局优势:
- 可以为不同的路由组使用不同的布局
- 可以更好地组织代码结构
- 不影响 URL 路径
4.2 Pages Router 基础(兼容旧项目,了解即可)
Pages Router 是 Next.js 13 之前的路由系统,基于文件命名定义路由。
基本路由
pages/index.js:首页(/)pages/about.js:关于页(/about)pages/blog/index.js:博客列表页(/blog)pages/blog/[id].js:博客详情页(/blog/1)
核心文件
pages/_app.js:应用入口,用于全局布局和状态pages/_document.js:HTML 文档模板,用于自定义 HTML 结构pages/api/:API 路由目录
示例
jsx
// pages/index.js
export default function Home() {
return <h1>Home Page</h1>;
}
// pages/about.js
export default function About() {
return <h1>About Page</h1>;
}
// pages/_app.js
import '../styles/globals.css';
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />;
}4.3 动态路由([id].js、[...slug].js 写法,实战高频)
基本动态路由
在 App Router 中,使用 [id] 文件夹创建动态路由。
示例:
app/
└── blog/
├── [id]/
│ └── page.js # /blog/1, /blog/2
└── page.js # /blog使用:
jsx
// app/blog/[id]/page.js
import { useParams } from 'next/navigation';
export default function BlogPost() {
const params = useParams();
const { id } = params;
return <h1>Blog Post {id}</h1>;
}捕获所有路由
使用 [...slug] 文件夹创建捕获所有路由,用于处理任意深度的路径。
示例:
app/
└── docs/
└── [...slug]/
└── page.js # /docs, /docs/guide, /docs/guide/getting-started使用:
jsx
// app/docs/[...slug]/page.js
import { useParams } from 'next/navigation';
export default function Docs() {
const params = useParams();
const { slug } = params;
return <h1>Docs: {slug?.join('/')}</h1>;
}可选捕获所有路由
使用 [[...slug]] 文件夹创建可选捕获所有路由,用于处理可选的路径。
示例:
app/
└── search/
└── [[...params]]/
└── page.js # /search, /search?q=nextjs, /search/category/tech4.4 嵌套路由(创建嵌套页面与嵌套布局,适配复杂页面结构)
嵌套路由允许你创建具有嵌套结构的页面,每个层级都可以有自己的布局。
示例:
app/
├── layout.js # 根布局
├── dashboard/
│ ├── layout.js # 仪表盘布局
│ ├── page.js # /dashboard
│ ├── settings/
│ │ ├── layout.js # 设置布局
│ │ └── page.js # /dashboard/settings
│ └── profile/
│ └── page.js # /dashboard/profile
└── page.js # /布局嵌套:
jsx
// app/dashboard/layout.js
export default function DashboardLayout({ children }) {
return (
<div className="dashboard">
<aside>
<nav>
<ul>
<li><a href="/dashboard">Overview</a></li>
<li><a href="/dashboard/settings">Settings</a></li>
<li><a href="/dashboard/profile">Profile</a></li>
</ul>
</nav>
</aside>
<main>{children}</main>
</div>
);
}4.5 路由参数与查询(useParams、useSearchParams 钩子获取)
useParams
用于获取动态路由参数。
示例:
jsx
import { useParams } from 'next/navigation';
export default function BlogPost() {
const params = useParams();
const { id } = params;
return <h1>Blog Post {id}</h1>;
}useSearchParams
用于获取 URL 查询参数。
示例:
jsx
import { useSearchParams } from 'next/navigation';
export default function SearchResults() {
const searchParams = useSearchParams();
const query = searchParams.get('q');
const category = searchParams.get('category');
return (
<div>
<h1>Search Results</h1>
<p>Query: {query}</p>
<p>Category: {category}</p>
</div>
);
}4.6 路由导航(Link 组件、编程式导航 useRouter)
Link 组件
用于客户端导航,支持预取功能,提升性能。
示例:
jsx
import Link from 'next/link';
export default function Navigation() {
return (
<nav>
<ul>
<li><Link href="/">Home</Link></li>
<li><Link href="/about">About</Link></li>
<li><Link href="/blog/1">Blog Post 1</Link></li>
</ul>
</nav>
);
}编程式导航
使用 useRouter 钩子进行编程式导航。
示例:
jsx
import { useRouter } from 'next/navigation';
export default function Navigation() {
const router = useRouter();
const handleNavigation = () => {
router.push('/about');
};
const handleBack = () => {
router.back();
};
const handleReplace = () => {
router.replace('/contact');
};
return (
<div>
<button onClick={handleNavigation}>Go to About</button>
<button onClick={handleBack}>Go Back</button>
<button onClick={handleReplace}>Replace with Contact</button>
</div>
);
}4.7 404 页面配置(not-found.js)与重定向(redirect 函数)
404 页面
在 App Router 中,使用 not-found.js 文件创建 404 页面。
示例:
jsx
// app/not-found.js
export default function NotFound() {
return (
<div>
<h1>404 - Page Not Found</h1>
<p>The page you are looking for does not exist.</p>
<a href="/">Go back to Home</a>
</div>
);
}重定向
使用 redirect 函数进行重定向。
示例:
jsx
// app/old-page/page.js
import { redirect } from 'next/navigation';
export default function OldPage() {
redirect('/new-page');
}
// app/admin/page.js
import { redirect } from 'next/navigation';
import { getSession } from '@/lib/auth';
export default async function AdminPage() {
const session = await getSession();
if (!session) {
redirect('/login');
}
return <h1>Admin Page</h1>;
}4.8 路由拦截与中间件(middleware.js 使用,如登录拦截、权限控制)
中间件允许你在请求到达页面之前执行代码,用于实现登录拦截、权限控制、国际化等功能。
创建中间件
在项目根目录创建 middleware.js 文件。
示例:
javascript
// middleware.js
import { NextResponse } from 'next/server';
// 定义需要保护的路由
const protectedRoutes = ['/dashboard', '/admin'];
export function middleware(request) {
const url = request.nextUrl;
const pathname = url.pathname;
// 检查是否访问受保护的路由
if (protectedRoutes.some(route => pathname.startsWith(route))) {
// 检查是否有认证令牌
const token = request.cookies.get('auth-token');
if (!token) {
// 重定向到登录页
return NextResponse.redirect(new URL('/login', url));
}
}
// 继续处理请求
return NextResponse.next();
}
// 配置中间件适用的路径
export const config = {
matcher: ['/dashboard/:path*', '/admin/:path*'],
};中间件功能
- 认证与授权:检查用户是否登录,是否有权限访问特定路由
- 国际化:根据用户语言偏好重定向到相应的语言版本
- A/B 测试:根据用户特征分发到不同的页面版本
- 日志记录:记录请求信息
小结
本章介绍了 Next.js 的路由系统,包括 App Router 和 Pages Router,以及动态路由、嵌套路由、路由参数、导航和中间件等内容。通过本章的学习,你应该已经掌握了:
- App Router 的核心概念:基于文件夹的路由、页面组件、布局组件和路由分组
- Pages Router 的基础用法(了解即可)
- 动态路由的创建和使用:基本动态路由、捕获所有路由和可选捕获所有路由
- 嵌套路由的创建和布局嵌套
- 路由参数和查询参数的获取:useParams 和 useSearchParams
- 路由导航的实现:Link 组件和编程式导航
- 404 页面的配置和重定向的实现
- 中间件的使用:登录拦截、权限控制等
Next.js 的路由系统是其核心优势之一,它提供了简洁、直观的路由定义方式,无需手动配置路由。在实际开发中,建议使用 App Router(Next.js 14 推荐),它提供了更现代化的路由体验和更好的性能。
接下来,我们将学习 Next.js 的页面与组件基础,包括页面组件、布局组件、静态资源处理等内容。
