跳转到内容

布局

布局是用于提供可复用 UI 结构(例如页面模板)的 Astro 组件

我们通常将提供跨页面共享的通用 UI 元素(如页眉、导航栏和页脚)的 Astro 组件称为“布局”。一个典型的 Astro 布局组件为 Astro、Markdown 或 MDX 页面提供:

  • 一个页面外壳<html><head><body> 标签)
  • 一个 <slot />,用于指定单个页面的内容应该被注入到哪里。

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

然而,如果一个布局组件确实包含一个页面外壳,它的 <html> 元素必须是该组件中所有其他元素的父元素。

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

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>
<style>
h1 {
font-size: 2rem;
}
</style>
</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>
了解更多关于插槽的信息。

任何 Astro 布局都可以通过为你的 props 提供类型来引入类型安全和自动补全。

src/components/MyLayout.astro
---
interface Props {
title: string;
description: string;
publishDate: string;
viewCount: number;
}
const { title, description, publishDate, viewCount } = Astro.props;
---
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="description" content={description}>
<title>{title}</title>
</head>
<body>
<header>
<p>Published on {publishDate}</p>
<p>Viewed by {viewCount} folks</p>
</header>
<main>
<slot />
</main>
</body>
</html>

页面布局对于独立的 Markdown 页面特别有用,否则这些页面将没有任何页面格式。

Astro 提供了一个特殊的 layout frontmatter 属性,专门用于位于 src/pages/ 内并使用基于文件路由的单个 .md 文件,以指定使用哪个 .astro 组件作为页面布局。这个组件允许你为 Markdown 页面提供 <head> 内容,如元标签(例如 <meta charset="utf-8">)和样式。默认情况下,这个指定的组件可以自动访问 Markdown 文件中的数据。

在使用内容集合查询和渲染内容时,这不会被识别为一个特殊的属性。

src/pages/page.md
---
layout: ../layouts/BlogPostLayout.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 Markdown files located within `src/pages/`.

Markdown 页面的典型布局包括:

  1. frontmatter 属性,用于访问 Markdown 页面的 frontmatter 和其他数据。
  2. 一个默认的 <slot />,用于指示页面的 Markdown 内容应该被渲染到哪里。
src/layouts/BlogPostLayout.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. -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<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>

你可以使用 MarkdownLayoutProps 辅助工具来设置布局的Props 类型

src/layouts/BlogPostLayout.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>
<meta charset="utf-8">
<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 布局将可以通过 Astro.props 访问以下信息:

  • file - 此文件的绝对路径(例如 /home/user/projects/.../file.md)。
  • url - 页面的 URL(例如 /zh-cn/guides/markdown-content)。
  • frontmatter - 来自 Markdown 或 MDX 文档的所有 frontmatter。
    • frontmatter.file - 与顶层的 file 属性相同。
    • frontmatter.url - 与顶层的 url 属性相同。
  • headings - Markdown 或 MDX 文档中标题(h1 -> h6)的列表,附带相关元数据。此列表遵循以下类型:{ depth: number; slug: string; text: string }[]
  • rawContent() - 一个返回原始 Markdown 文档字符串的函数。
  • compiledContent() - 一个异步函数,返回编译为 HTML 字符串的 Markdown 文档。

你也可以在 MDX 文件的 frontmatter 中使用特殊的 Markdown 布局属性,以同样的方式将 frontmatterheadings 属性直接传递给指定的布局组件。

要将 frontmatter 中不存在(或不能存在)的信息传递给你的 MDX 布局,你可以导入并使用 <Layout /> 组件。这与其他 Astro 组件一样工作,并且不会自动接收任何 props。直接将任何必要的 props 传递给它:

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';
export 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 /> 组件的位置:

src/layouts/BaseLayout.astro
---
const { title, fancyJsHelper } = Astro.props;
---
<html>
<head>
<!-- -->
<meta charset="utf-8">
</head>
<body>
<!-- -->
<h1>{title}</h1>
<slot /> <!-- your content is injected here -->
<p>{fancyJsHelper()}</p>
<!-- -->
</body>
</html>

当使用任何布局时(无论是通过 frontmatter 的 layout 属性还是通过导入布局),你都必须在布局中包含 <meta charset="utf-8"> 标签,因为 Astro 将不再自动将其添加到你的 MDX 页面中。

在我们的 Markdown 指南中了解更多关于 Astro 的 Markdown 和 MDX 支持的信息。

布局组件不需要包含整个页面的 HTML。你可以将布局分解成更小的组件,并组合布局组件来创建更灵活的页面模板。当你想在多个布局之间共享一些代码时,这种模式非常有用。

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

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>
贡献 社区 赞助