Skip to content

第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/tech

4.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>
  );
}

用于客户端导航,支持预取功能,提升性能。

示例

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,以及动态路由、嵌套路由、路由参数、导航和中间件等内容。通过本章的学习,你应该已经掌握了:

  1. App Router 的核心概念:基于文件夹的路由、页面组件、布局组件和路由分组
  2. Pages Router 的基础用法(了解即可)
  3. 动态路由的创建和使用:基本动态路由、捕获所有路由和可选捕获所有路由
  4. 嵌套路由的创建和布局嵌套
  5. 路由参数和查询参数的获取:useParams 和 useSearchParams
  6. 路由导航的实现:Link 组件和编程式导航
  7. 404 页面的配置和重定向的实现
  8. 中间件的使用:登录拦截、权限控制等

Next.js 的路由系统是其核心优势之一,它提供了简洁、直观的路由定义方式,无需手动配置路由。在实际开发中,建议使用 App Router(Next.js 14 推荐),它提供了更现代化的路由体验和更好的性能。

接下来,我们将学习 Next.js 的页面与组件基础,包括页面组件、布局组件、静态资源处理等内容。

© 2026 编程马·菜鸟教程 版权所有