佈局與頁面
Next.js 使用基於檔案系統的路由,這意味著你可以使用資料夾和檔案來定義路由。本頁將指導你如何建立佈局和頁面,以及如何在其間進行連結。
建立頁面
頁面是在特定路由上渲染的 UI。要建立一個頁面,在 app 目錄下新增一個 page 檔案並預設匯出 React 元件。例如,要建立一個索引頁面 (/)

export default function Page() {
return <h1>Hello Next.js!</h1>
}建立佈局
佈局是在多個頁面之間共享的 UI。在導航時,佈局會保留狀態、保持互動性並且不會重新渲染。
你可以透過從 layout 檔案預設匯出 React 元件來定義佈局。該元件應接受一個 children 屬性,它可以是一個頁面或另一個佈局。
例如,要建立一個接受索引頁面作為子元件的佈局,請在 app 目錄下新增一個 layout 檔案

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 標籤。
建立巢狀路由
巢狀路由是由多個 URL 片段組成的路由。例如,/blog/[slug] 路由由三個片段組成
/(根片段)blog(片段)[slug](葉片段)
在 Next.js 中
- 資料夾用於定義對映到 URL 片段的路由片段。
- 檔案(如
page和layout)用於建立在片段中顯示的 UI。
要建立巢狀路由,你可以將資料夾相互巢狀。例如,要新增 /blog 路由,請在 app 目錄中建立一個名為 blog 的資料夾。然後,為了使 /blog 可以公開訪問,新增一個 page.tsx 檔案

// Dummy imports
import { getPosts } from '@/lib/posts'
import { Post } from '@/ui/post'
export default async function Page() {
const posts = await getPosts()
return (
<ul>
{posts.map((post) => (
<Post key={post.id} post={post} />
))}
</ul>
)
}你可以繼續巢狀資料夾以建立巢狀路由。例如,要為特定部落格文章建立路由,請在 blog 內部建立一個新的 [slug] 資料夾並新增一個 page 檔案

function generateStaticParams() {}
export default function Page() {
return <h1>Hello, Blog Post Page!</h1>
}將資料夾名稱用方括號括起來(例如 [slug])會建立一個動態路由片段,用於根據資料生成多個頁面。例如,部落格文章、產品頁面等。
巢狀佈局
預設情況下,資料夾層次結構中的佈局也是巢狀的,這意味著它們透過其 children 屬性包裝子佈局。你可以透過在特定路由片段(資料夾)內新增 layout 來巢狀佈局。
例如,要為 /blog 路由建立一個佈局,請在 blog 資料夾中新增一個新的 layout 檔案。

export default function BlogLayout({
children,
}: {
children: React.ReactNode
}) {
return <section>{children}</section>
}如果你將上述兩個佈局組合起來,根佈局 (app/layout.js) 將會包裹部落格佈局 (app/blog/layout.js),而部落格佈局又會包裹部落格 (app/blog/page.js) 和部落格文章頁面 (app/blog/[slug]/page.js)。
建立動態片段
動態片段允許您建立從資料生成的路由。例如,您可以建立一個動態片段,根據部落格文章資料生成路由,而不是手動為每篇部落格文章建立路由。
要建立動態片段,請將片段(資料夾)名稱用方括號括起來:[segmentName]。例如,在 app/blog/[slug]/page.tsx 路由中,[slug] 就是動態片段。
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>
)
}巢狀在動態片段中的佈局也可以訪問 params 屬性。
使用搜索引數渲染
在伺服器元件頁面中,您可以使用searchParams屬性訪問搜尋引數
export default async function Page({
searchParams,
}: {
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}) {
const filters = (await searchParams).filters
}使用 searchParams 會使您的頁面進入動態渲染,因為它需要傳入請求來讀取搜尋引數。
客戶端元件可以使用 useSearchParams 鉤子來讀取搜尋引數。
瞭解更多關於 useSearchParams 在靜態渲染和動態渲染路由中的使用。
何時使用以及如何使用
- 當你需要搜尋引數來載入頁面資料(例如,分頁、從資料庫過濾)時,使用
searchParams屬性。 - 當搜尋引數僅在客戶端使用(例如,過濾已透過屬性載入的列表)時,使用
useSearchParams。 - 作為一項小最佳化,你可以在回撥函式或事件處理器中使用
new URLSearchParams(window.location.search)來讀取搜尋引數,而不會觸發重新渲染。
頁面間連結
你可以使用 <Link> 元件在路由之間進行導航。<Link> 是一個內建的 Next.js 元件,它擴充套件了 HTML <a> 標籤,提供了預取和客戶端導航。
例如,要生成部落格文章列表,從 next/link 匯入 <Link> 並向元件傳遞一個 href 屬性
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鉤子進行更高階的導航。
路由屬性輔助函式
Next.js 提供了實用工具型別,可從你的路由結構中推斷出 params 和命名槽
- PageProps:
page元件的屬性,包括params和searchParams。 - LayoutProps:
layout元件的屬性,包括children和任何命名槽(例如@analytics等資料夾)。
這些是全域性可用的輔助函式,在執行 next dev、next build 或 next typegen 時生成。
export default async function Page(props: PageProps<'/blog/[slug]'>) {
const { slug } = await props.params
return <h1>Blog post: {slug}</h1>
}export default function Layout(props: LayoutProps<'/dashboard'>) {
return (
<section>
{props.children}
{/* If you have app/dashboard/@analytics, it appears as a typed slot: */}
{/* {props.analytics} */}
</section>
)
}須知
- 靜態路由會將
params解析為{}。PageProps和LayoutProps是全域性輔助工具——無需匯入。- 型別在
next dev、next build或next typegen期間生成。
這有幫助嗎?




