Next.js 使用基于文件系统的路由,这意味着您可以使用文件夹和文件来定义路由。本页面将指导您如何创建布局和页面,以及如何在它们之间建立链接
创建 Page
页面是在特定路由上渲染的 UI。要创建页面,请在 app 目录中添加一个 page 文件,并默认导出一个 React 组件。例如,要创建索引页 (/):

创建 Layout
布局是多个页面之间共享的 UI。导航时,布局会保留状态、保持交互性,并且不会重新渲染
你可以通过从 layout 文件默认导出 React 组件来定义布局。该组件应该接受 children 属性,该属性可以是页面或其他布局
例如,要创建接受索引页作为子页的布局,请在 app 目录中添加 layout 文件:

// app/layout.tsx
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{/* Layout UI */}
{/* Place children where you want to render a page or nested layout */}
<main>{children}</main>
</body>
</html>
)
}上面的布局称为根布局,因为它定义在 app 目录的根目录下。根布局是必需的,并且必须包含 html 和 body 标签
创建嵌套路线 (nested route)
嵌套路由是由多个 URL 段组成的路由。例如,/blog/[slug] 路由由三个段组成:
/(Root Segment)blog(Segment)[slug](Leaf Segment)
在 Next.js 中:
- 文件夹用于定义映射到 URL 段的路由段
- 文件(如
page和layout)用于创建为某个片段显示的 UI
要创建嵌套路由,您可以将文件夹嵌套在一起。例如,要为 /blog 添加路由,请在 app 目录中创建一个名为 blog 文件夹。然后,要使 /blog 可公开访问,请添加一个 page.tsx 文件
您可以继续嵌套文件夹来创建嵌套路由。例如,要为特定博客文章创建路由,请在 blog 中创建一个新的 [slug] 文件夹并添加一个 page 文件

将文件夹名称括在方括号中(例如 [slug])会创建一个动态路由段,用于根据数据生成多个页面,例如博客文章、产品页面等
嵌套布局 (Nesting layouts)
默认情况下,文件夹层次结构中的布局也是嵌套的,这意味着它们通过其 children 属性包裹子布局。您可以通过在特定的路由段(文件夹)内添加 layout 来嵌套布局
例如,要为 /blog 路由创建布局,请在 blog 文件夹中添加一个新的 layout 文件
如果您要组合上述两个布局,根布局 (app/layout.js) 将包装博客布局 (app/blog/layout.js),后者将包装博客 (app/blog/page.js) 和博客文章页面 (app/blog/[slug]/page.js)

创建动态路由段 (dynamic segment)
动态路由段允许您创建基于数据生成的路由。例如,您无需为每篇博客文章手动创建路由,而是可以创建一个动态路由段,根据博客文章数据生成路由
要创建动态路由段,请将片段(文件夹)名称括在方括号中:[segmentName]。例如,在 app/blog/[slug]/page.tsx 路由中, [slug] 就是动态路由段
// app/blog/[slug]/page.tsx
export default async function BlogPostPage({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params
const post = await getPost(slug)
return (
<div>
<h1>{post.title}</h1>
<p>{post.content}</p>
</div>
)
}动态路由段的 layout.js 等文件都是能获取到 params props 的
Rendering with search params
在服务器组件 Page 中,可以使用 searchParams 属性访问搜索参数:
// app/page.tsx
export default async function Page({ searchParams }: { searchParams: Promise<{ [key: string]: string | string[] | undefined }> }) {
const filters = (await searchParams).filters
}使用 searchParams 会使您的页面进入动态渲染,因为它需要传入请求来读取搜索参数
客户端组件可以使用 useSearchParams 钩子读取搜索参数
何时使用?
- 当您需要搜索参数来加载页面数据(例如分页、从数据库过滤)时
- 当搜索参数仅在客户端使用时使用
useSearchParams(例如,过滤已通过 props 加载的列表) - 作为一项小优化,您可以在回调或事件处理程序中使用
new URLSearchParams(window.location.search)来读取搜索参数,而无需触发重新渲染
页面之间的链接
您可以使用 <Link> 组件在路由之间导航。<Link> 是一个内置的 Next.js 组件,它扩展了 HTML <a> 标签以提供预取和客户端导航
例如,要生成博客文章列表,请从 next/link 导入 <Link> ,并将 href 属性传递给组件:
// app/ui/post.tsx
import Link from 'next/link'
export default async function Post({ post }) {
const posts = await getPosts()
return (
<ul>
{posts.map(post => (
<li key={post.slug}>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
</li>
))}
</ul>
)
}温馨提示:<Link> 是 Next.js 中路由导航的主要方式。您还可以使用 useRouter 钩子进行更高级的导航