如何创建布局和页面

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 钩子 进行更高级的导航。