Skip to content

布局

布局Astro 组件 用于提供可重用的 UI 结构,例如页面模板。

Layouts are Astro components used to provide a reusable UI structure, such as a page template.

我们通常使用术语 “layout” 来表示 Astro 组件,这些组件提供跨页面共享的通用 UI 元素,例如页眉、导航栏和页脚。 典型的 Astro 布局组件为 Astro、Markdown 或 MDX 页面 提供:

  • a 页面外壳<html><head><body> 标签)
  • <slot /> 指定应在何处注入各个页面内容。

但是,布局组件没有什么特别的! 它们可以像任何其他 Astro 组件一样使用 接受属性导入和使用其他组件。 它们可以包括 UI 框架组件客户端脚本。 它们甚至不必提供完整的页面 shell,而是可以用作部分 UI 模板。

布局组件通常放置在项目中的 src/layouts 目录中以便组织,但这不是必需的; 你可以选择将它们放置在项目中的任何位置。 你甚至可以通过 在布局名称前添加 _ 前缀 将布局组件与页面并置。

Layout components are commonly placed in a src/layouts directory in your project for organization, but this is not a requirement; you can choose to place them anywhere in your project. You can even colocate layout components alongside your pages by prefixing the layout names with _.

src/layouts/MySiteLayout.astro
---
import BaseHead from '../components/BaseHead.astro';
import Footer from '../components/Footer.astro';
const { title } = Astro.props
---
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<BaseHead title={title}/>
</head>
<body>
<nav>
<a href="#">Home</a>
<a href="#">Posts</a>
<a href="#">Contact</a>
</nav>
<h1>{title}</h1>
<article>
<slot /> <!-- your content is injected here -->
</article>
<Footer />
</body>
</html>
src/pages/index.astro
---
import MySiteLayout from '../layouts/MySiteLayout.astro';
---
<MySiteLayout title="Home Page">
<p>
My page content, wrapped in a layout!
</p>
</MySiteLayout>

📚 了解有关 slots 的更多信息。

📚 Learn more about slots.

页面布局对于 Markdown 和 MDX 页面 特别有用,否则它不会有任何页面格式。

Page layouts are especially useful for Markdown and MDX pages which otherwise would not have any page formatting.

Astro 提供了一个特殊的 layout frontmatter 属性来指定使用哪个 .astro 组件作为页面布局。

Astro provides a special layout frontmatter property to specify which .astro component to use as the page layout.

src/pages/page.md
---
layout: ../layouts/BaseLayout.astro
title: "Hello, World!"
author: "Matthew Phillips"
date: "09 Aug 2022"
---
All frontmatter properties are available as props to an Astro layout component.
The `layout` property is the only special one provided by Astro.
You can use it in both Markdown and MDX files located within `src/pages/`.

Markdown 或 MDX 页面的典型布局包括:

A typical layout for Markdown or MDX pages includes:

  1. frontmatter 属性用于访问 Markdown 或 MDX 页面的 frontmatter 和其他数据。
  2. 默认 <slot /> 指示页面的 Markdown/MDX 内容应渲染的位置。
src/layouts/BaseLayout.astro
---
// 1. The frontmatter prop gives access to frontmatter and other data
const { frontmatter } = Astro.props;
---
<html>
<head>
<!-- Add other Head elements here, like styles and meta tags. -->
<title>{frontmatter.title}</title>
</head>
<body>
<!-- Add other UI components here, like common headers and footers. -->
<h1>{frontmatter.title} by {frontmatter.author}</h1>
<!-- 2. Rendered HTML will be passed into the default slot. -->
<slot />
<p>
Written on: {frontmatter.date}
</p>
</body>
</html>

你可以使用 MarkdownLayoutPropsMDXLayoutProps 辅助程序设置布局的 Props

You can set a layout’s Props type with the MarkdownLayoutProps or MDXLayoutProps helper:

src/layouts/BaseLayout.astro
---
import type { MarkdownLayoutProps } from 'astro';
type Props = MarkdownLayoutProps<{
// Define frontmatter props here
title: string;
author: string;
date: string;
}>;
// Now, `frontmatter`, `url`, and other Markdown layout properties
// are accessible with type safety
const { frontmatter, url } = Astro.props;
---
<html>
<head>
<link rel="canonical" href={new URL(url, Astro.site).pathname}>
<title>{frontmatter.title}</title>
</head>
<body>
<h1>{frontmatter.title} by {frontmatter.author}</h1>
<slot />
<p>
Written on: {frontmatter.date}
</p>
</body>
</html>

Markdown/MDX 布局将可以通过 Astro.props 访问以下信息:

A Markdown/MDX layout will have access to the following information via Astro.props:

  • file - 该文件的绝对路径(例如 /home/user/projects/.../file.md)。
  • url - 如果是页面,则为页面的 URL(例如 /en/guides/markdown-content)。
  • frontmatter - Markdown 或 MDX 文档中的所有 frontmatter。
    • frontmatter.file - 与顶层 file 属性相同。
    • frontmatter.url - 与顶层 url 属性相同。
  • headings - Markdown 或 MDX 文档中的标题 (h1 -> h6) 列表以及关联的元数据。 该列表遵循以下类型: { depth: number; slug: string; text: string }[]
  • (仅限 Markdown)rawContent() - 以字符串形式返回原始 Markdown 文档的函数。
  • (仅限 Markdown)compiledContent() - 返回编译为 HTML 字符串的 Markdown 文档的函数。

示例 Markdown 博客文章可能会将以下 Astro.props 对象传递到其布局:

An example Markdown blog post may pass the following Astro.props object to its layout:

Astro.props = {
file: "/home/user/projects/.../file.md",
url: "/en/guides/markdown-content/",
frontmatter: {
/** Frontmatter from a blog post */
title: "Astro 0.18 Release",
date: "Tuesday, July 27 2021",
author: "Matthew Phillips",
description: "Astro 0.18 is our biggest release since Astro launch.",
/** Generated values */
file: "/home/user/projects/.../file.md",
url: "/en/guides/markdown-content/"
},
headings: [
{
"depth": 1,
"text": "Astro 0.18 Release",
"slug": "astro-018-release"
},
{
"depth": 2,
"text": "Responsive partial hydration",
"slug": "responsive-partial-hydration"
}
/* ... */
],
/** Available in Markdown only */
rawContent: () => "# Astro 0.18 Release\nA little over a month ago, the first public beta [...]",
compiledContent: () => "<h1>Astro 0.18 Release</h1>\n<p>A little over a month ago, the first public beta [...]</p>",
}

:::note 注意 Markdown/MDX 布局将可以访问其所有文件的 导出的属性Astro.props 有一些关键的区别:

A Markdown/MDX layout will have access to all its file’s exported properties from Astro.props with some key differences:

  • 标题信息(即 h1 -> h6 元素)可通过 headings 数组而不是 getHeadings() 函数获得。

  • fileurl 也可用作嵌套 frontmatter 属性(即 frontmatter.urlfrontmatter.file)。

  • 在 frontmatter 之外定义的值(例如 MDX 中的 export 语句)不可用。 请考虑 导入布局。 :::

你可能需要将 Frontmatter 中不存在(或不能)存在的信息传递到 MDX 布局。 在这种情况下,你可以导入并使用 <Layout /> 组件 并像任何其他组件一样向它传递 props:

You may need to pass information to your MDX layout that does not (or cannot) exist in your frontmatter. In this case, you can instead import and use a <Layout /> component and pass it props like any other component:

src/pages/posts/first-post.mdx
---
layout: ../../layouts/BaseLayout.astro
title: 'My first MDX post'
publishDate: '21 September 2022'
---
import BaseLayout from '../../layouts/BaseLayout.astro';
function fancyJsHelper() {
return "Try doing that with YAML!";
}
<BaseLayout title={frontmatter.title} fancyJsHelper={fancyJsHelper}>
Welcome to my new Astro blog, using MDX!
</BaseLayout>

然后,你可以通过布局中的 Astro.props 使用你的值,并且你的 MDX 内容将被注入到写入 <slot /> 组件的页面中:

Then, your values are available to you through Astro.props in your layout, and your MDX content will be injected into the page where your <slot /> component is written:

src/layouts/BaseLayout.astro
---
const { title, fancyJsHelper } = Astro.props;
---
<!-- -->
<h1>{title}</h1>
<slot /> <!-- your content is injected here -->
<p>
{fancyJsHelper()}
</p>
<!-- -->

📚 在我们的 Markdown/MDX guide 中了解有关 Astro 的 Markdown 和 MDX 支持的更多信息。

📚 Learn more about Astro’s Markdown and MDX support in our Markdown/MDX guide.

.md.mdx.astro 使用一种布局

Section titled 对 .md、.mdx 和 .astro 使用一种布局

可以编写单个 Astro 布局来接收来自 .md.mdx 文件的 frontmatter 对象,以及从 .astro 文件传递的任何命名属性。

A single Astro layout can be written to receive the frontmatter object from .md and .mdx files, as well as any named props passed from .astro files.

在下面的示例中,布局将显示来自 frontmatter YAML title 属性或来自传递 title 属性的 Astro 组件的页面标题:

In the example below, the layout will display the page title either from a frontmatter YAML title property or from an Astro component passing a title attribute:

src/components/MyLayout.astro
---
const { title } = Astro.props.frontmatter || Astro.props;
---
<html>
<head></head>
<body>
<h1>{title}</h1>
<slot />
</body>
</html>

布局组件不需要包含整个页面的 HTML。 你可以将布局分解为更小的组件,并组合布局组件以创建更灵活的页面模板。 当你想要跨多个布局共享某些代码时,此模式非常有用。

Layout components do not need to contain an entire page worth of HTML. You can break your layouts into smaller components, and combine layout components to create even more flexible, page templates. This pattern is useful when you want to share some code across multiple layouts.

例如,BlogPostLayout.astro 布局组件可以设置帖子标题、日期和作者的样式。 然后,站点范围的 BaseLayout.astro 可以处理页面模板的其余部分,例如导航、页脚、SEO 元标记、全局样式和字体。 你还可以将从帖子收到的属性传递到另一个布局,就像任何其他嵌套组件一样。

For example, a BlogPostLayout.astro layout component could style a post’s title, date and author. Then, a site-wide BaseLayout.astro could handle the rest of your page template, like navigation, footers, SEO meta tags, global styles, and fonts. You can also pass props received from your post to another layout, just like any other nested component.

src/layouts/BlogPostLayout.astro
---
import BaseLayout from './BaseLayout.astro'
const {frontmatter} = Astro.props;
---
<BaseLayout url={frontmatter.url}>
<h1>{frontmatter.title}</h1>
<h2>Post author: {frontmatter.author}</h2>
<slot />
</BaseLayout>