如何建立版面配置和頁面

Next.js 使用基於檔案系統的路由,這意味著您可以使用資料夾和檔案來定義路由。本頁將指導您如何建立版面配置和頁面,並在它們之間建立連結。

建立頁面

頁面是在特定路由上渲染的使用者介面。要建立頁面,請在 app 目錄中新增一個 page 檔案,並預設導出一個 React 元件。例如,要建立首頁 (/):

page.js 特殊檔案
export default function Page() {
  return <h1>Hello Next.js!</h1>
}
export default function Page() {
  return <h1>Hello Next.js!</h1>
}

建立版面配置

版面配置是共享於多個頁面之間的使用者介面。在導航時,版面配置會保留狀態、保持互動性且不會重新渲染。

您可以透過從 layout 檔案預設導出一個 React 元件來定義版面配置。該元件應接受一個 children 屬性,該屬性可以是頁面或另一個嵌套版面配置

例如,要建立一個接受首頁作為子元件的版面配置,請在 app 目錄中新增一個 layout 檔案:

layout.js 特殊檔案
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        {/* 版面配置 UI */}
        {/* 將 children 放在您想要渲染頁面或嵌套版面配置的位置 */}
        <main>{children}</main>
      </body>
    </html>
  )
}
export default function DashboardLayout({ children }) {
  return (
    <html lang="en">
      <body>
        {/* 版面配置 UI */}
        {/* 將 children 放在您想要渲染頁面或嵌套版面配置的位置 */}
        <main>{children}</main>
      </body>
    </html>
  )
}

上述版面配置稱為根版面配置,因為它定義在 app 目錄的根目錄中。根版面配置是必需的,且必須包含 htmlbody 標籤。

建立嵌套路由

嵌套路由是由多個 URL 區段組成的路由。例如,/blog/[slug] 路由由三個區段組成:

  • / (根區段)
  • blog (區段)
  • [slug] (葉區段)

在 Next.js 中:

  • 資料夾用於定義對應於 URL 區段的路由區段。
  • 檔案(如 pagelayout)用於建立顯示在區段上的使用者介面。

要建立嵌套路由,您可以將資料夾嵌套在彼此內部。例如,要新增 /blog 的路由,請在 app 目錄中建立一個名為 blog 的資料夾。然後,要使 /blog 公開可訪問,請新增一個 page.tsx 檔案:

顯示 blog 資料夾和 page.js 檔案的檔案層次結構
// 虛擬導入
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>
  )
}
// 虛擬導入
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 檔案:

顯示 blog 資料夾內嵌套 slug 資料夾和 page.js 檔案的檔案層次結構
function generateStaticParams() {}

export default function Page() {
  return <h1>Hello, Blog Post Page!</h1>
}
function generateStaticParams() {}

export default function Page() {
  return <h1>Hello, Blog Post Page!</h1>
}

將資料夾名稱用方括號包裹(例如 [slug])會建立一個動態路由區段,用於從資料生成多個頁面。例如,部落格文章、產品頁面等。

嵌套版面配置

預設情況下,資料夾層次結構中的版面配置也是嵌套的,這意味著它們會透過 children 屬性包裹子版面配置。您可以透過在特定路由區段(資料夾)內新增 layout 來嵌套版面配置。

例如,要為 /blog 路由建立版面配置,請在 blog 資料夾內新增一個 layout 檔案。

顯示根版面配置包裹 blog 版面配置的檔案層次結構
export default function BlogLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return <section>{children}</section>
}
export default function BlogLayout({ children }) {
  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>
  )
}
export default async function BlogPostPage({ params }) {
  const { slug } = await params
  const post = await getPost(slug)

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  )
}

了解更多關於動態區段的資訊。

在頁面之間建立連結

您可以使用 <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>
  )
}
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 鉤子進行更進階的導航。