布局
布局是用于提供可复用 UI 结构(例如页面模板)的 Astro 组件。
我们通常将提供跨页面共享的通用 UI 元素(如页眉、导航栏和页脚)的 Astro 组件称为“布局”。一个典型的 Astro 布局组件为 Astro、Markdown 或 MDX 页面提供:
- 一个页面外壳(
<html>
、<head>
和<body>
标签) - 一个
<slot />
,用于指定单个页面的内容应该被注入到哪里。
但是,布局组件并没有什么特别之处!它们可以像任何其他 Astro 组件一样接受属性以及导入和使用其他组件。它们可以包含UI 框架组件和客户端脚本。它们甚至不必提供完整的页面外壳,而是可以作为部分 UI 模板使用。
然而,如果一个布局组件确实包含一个页面外壳,它的 <html>
元素必须是该组件中所有其他元素的父元素。
为了方便组织,布局组件通常放置在项目的 src/layouts
目录中,但这不是必需的;你可以选择将它们放置在项目中的任何位置。你甚至可以通过为布局名称添加下划线前缀 _
将布局组件与页面放在一起。
布局示例
标题为“布局示例”的部分---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>
---import MySiteLayout from '../layouts/MySiteLayout.astro';---<MySiteLayout title="Home Page"> <p>My page content, wrapped in a layout!</p></MySiteLayout>
在布局中使用 TypeScript
标题为“在布局中使用 TypeScript”的部分任何 Astro 布局都可以通过为你的 props 提供类型来引入类型安全和自动补全。
---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 布局
标题为“Markdown 布局”的部分页面布局对于独立的 Markdown 页面特别有用,否则这些页面将没有任何页面格式。
Astro 提供了一个特殊的 layout
frontmatter 属性,专门用于位于 src/pages/
内并使用基于文件路由的单个 .md
文件,以指定使用哪个 .astro
组件作为页面布局。这个组件允许你为 Markdown 页面提供 <head>
内容,如元标签(例如 <meta charset="utf-8">
)和样式。默认情况下,这个指定的组件可以自动访问 Markdown 文件中的数据。
在使用内容集合查询和渲染内容时,这不会被识别为一个特殊的属性。
---layout: ../layouts/BlogPostLayout.astrotitle: "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 页面的典型布局包括:
frontmatter
属性,用于访问 Markdown 页面的 frontmatter 和其他数据。- 一个默认的
<slot />
,用于指示页面的 Markdown 内容应该被渲染到哪里。
---// 1. The frontmatter prop gives access to frontmatter and other dataconst { 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
类型。
---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 safetyconst { 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 布局属性
标题为“Markdown 布局属性”的部分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 文档。
Markdown 布局将可以通过 Astro.props
访问 Markdown 文件的所有可用属性,但有两个关键区别:
-
标题信息(即
h1 -> h6
元素)可通过headings
数组获得,而不是通过getHeadings()
函数。 -
file
和url
也可以作为嵌套的frontmatter
属性(即frontmatter.url
和frontmatter.file
)使用。
手动导入布局 (MDX)
标题为“手动导入布局 (MDX)”的部分你也可以在 MDX 文件的 frontmatter 中使用特殊的 Markdown 布局属性,以同样的方式将 frontmatter
和 headings
属性直接传递给指定的布局组件。
要将 frontmatter 中不存在(或不能存在)的信息传递给你的 MDX 布局,你可以导入并使用 <Layout />
组件。这与其他 Astro 组件一样工作,并且不会自动接收任何 props。直接将任何必要的 props 传递给它:
---layout: ../../layouts/BaseLayout.astrotitle: '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 />
组件的位置:
---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 页面中。
嵌套布局
标题为“嵌套布局”的部分布局组件不需要包含整个页面的 HTML。你可以将布局分解成更小的组件,并组合布局组件来创建更灵活的页面模板。当你想在多个布局之间共享一些代码时,这种模式非常有用。
例如,一个 BlogPostLayout.astro
布局组件可以为文章的标题、日期和作者设置样式。然后,一个全站范围的 BaseLayout.astro
可以处理页面模板的其余部分,如导航、页脚、SEO 元标签、全局样式和字体。你还可以像处理任何其他嵌套组件一样,将从文章接收到的 props 传递给另一个布局。
---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>