跳到主要内容

如何创建布局和页面

Next.js 使用基于文件系统的路由,这意味着你可以使用文件夹和文件来定义路由。本页将指导你如何创建布局和页面,以及它们之间的链接。

¥Next.js uses file-system based routing, meaning you can use folders and files to define routes. This page will guide you through how to create layouts and pages, and link between them.

创建页面

¥Creating a page

页面是在特定路由上渲染的 UI。要创建页面,请在 app 目录中添加 page 文件 并默认导出 React 组件。例如,要创建索引页 (/):

¥A page is UI that is rendered on a specific route. To create a page, add a page file inside the app directory and default export a React component. For example, to create an index page (/):

export default function Page() {
return <h1>Hello Next.js!</h1>
}
export default function Page() {
return <h1>Hello Next.js!</h1>
}

创建布局

¥Creating a layout

布局是多个页面之间共享的 UI。在导航时,布局会保留状态、保持交互性,并且不会重新渲染。

¥A layout is UI that is shared between multiple pages. On navigation, layouts preserve state, remain interactive, and do not rerender.

你可以通过默认从 layout 文件 导出 React 组件来定义布局。组件应接受 children prop,可以是页面或另一个 layout

¥You can define a layout by default exporting a React component from a layout file. The component should accept a children prop which can be a page or another layout.

例如,要创建一个接受索引页作为子页面的布局,请在 app 目录中添加一个 layout 文件:

¥For example, to create a layout that accepts your index page as child, add a layout file inside the app directory:

export default function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>


<main>{children}</main>
</body>
</html>
)
}
export default function DashboardLayout({ children }) {
return (
<html lang="en">
<body>


<main>{children}</main>
</body>
</html>
)
}

上面的布局称为 根布局,因为它是在 app 目录的根目录中定义的。根布局是必需的,并且必须包含 htmlbody 标签。

¥The layout above is called a root layout because it's defined at the root of the app directory. The root layout is required and must contain html and body tags.

创建嵌套路由

¥Creating a nested route

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

¥A nested route is a route composed of multiple URL segments. For example, the /blog/[slug] route is composed of three segments:

  • /(根段)

    ¥/ (Root Segment)

  • blog(片段)

    ¥blog (Segment)

  • [slug](叶段)

    ¥[slug] (Leaf Segment)

在 Next.js 中:

¥In Next.js:

  • 文件夹用于定义映射到 URL 段的路由段。

    ¥Folders are used to define the route segments that map to URL segments.

  • 文件(如 pagelayout)用于创建为片段显示的 UI。

    ¥Files (like page and layout) are used to create UI that is shown for a segment.

要创建嵌套路由,你可以将文件夹嵌套在一起。例如,要为 /blog 添加路由,请在 app 目录中创建一个名为 blog 的文件夹。然后,要使 /blog 可公开访问,请添加 page 文件:

¥To create nested routes, you can nest folders inside each other. For example, to add a route for /blog, create a folder called blog in the app directory. Then, to make /blog publicly accessible, add a page file:

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 文件:

¥You can continue nesting folders to create nested routes. For example, to create a route for a specific blog post, create a new [slug] folder inside blog and add a page file:

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])会创建一个特殊的 动态路由段,用于从数据生成多个页面。这对于博客文章、产品页面等很有用。

¥Good to know: Wrapping a folder name in square brackets (e.g. [slug]) creates a special dynamic route segment used to generate multiple pages from data. This is useful for blog posts, product pages, etc.

嵌套布局

¥Nesting layouts

默认情况下,文件夹层次结构中的布局也是嵌套的,这意味着它们通过其 children 属性封装子布局。你可以通过在特定路由段(文件夹)内添加 layout 来嵌套布局。

¥By default, layouts in the folder hierarchy are also nested, which means they wrap child layouts via their children prop. You can nest layouts by adding layout inside specific route segments (folders).

例如,要为 /blog 路由创建布局,请在 blog 文件夹内添加一个新的 layout 文件。

¥For example, to create a layout for the /blog route, add a new layout file inside the blog folder.

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)。

¥If you were to combine the two layouts above, the root layout (app/layout.js) would wrap the blog layout (app/blog/layout.js), which would wrap the blog (app/blog/page.js) and blog post page (app/blog/[slug]/page.js).

页面之间的链接

¥Linking between pages

你可以使用 <Link> 组件 在路由之间导航。<Link> 是一个内置的 Next.js 组件,它扩展了 HTML <a> 标记以提供预取和客户端导航。

¥You can use the <Link> component to navigate between routes. <Link> is a built-in Next.js component that extends the HTML <a> tag to provide prefetching and client-side navigation.

例如,要生成博客文章列表,请从 next/link 导入 <Link> 并将 href 属性传递给组件:

¥For example, to generate a list of blog posts, import <Link> from next/link and pass a href prop to the component:

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

¥<Link> is the primary and recommended way to navigate between routes in your Next.js application. However, you can also use the useRouter hook for more advanced navigation.