跳转到内容

Astro 中的 Markdown

Markdown 通常用于创作文本繁重的内容,如博客文章和文档。Astro 包括对 Markdown 文件的内置支持,这些文件还可以包括 frontmatter YAML 来定义自定义属性,例如标题、描述和标签。

在 Astro 中,你可以在 GitHub 风格的 Markdown 中创作内容,然后在 .astro 组件中渲染它。它结合了为内容设计熟悉的书写格式、 Astro 组件语法以及架构的灵活性。

你的本地 Markdown 文件可以保存在 src/ 目录中的任何位置。要将单个本地的 Markdown 文件的导入到 .astro 组件,可以使用 import 语句来实现,而要想一次性查询多个文件,则可以使用 Vite 的 import.meta.glob()

如果你有一组相关的 Markdown 文件,可以考虑 将它们定义为集合。这将为你提供一些便利,其中包括了能够将 Markdown 文件存储在文件系统上的任何位置或使用远程存储。

集合还允许你使用专注于内容的优化 API 来查询和呈现你的内容。集合适用于共享相同结构的数据集,例如博客文章或产品项。当你在 schema 中定义集合时,还可以在编辑器中获得验证、类型安全和智能提示。

类 JSX 的动态表达式

段落标题 类 JSX 的动态表达式

导入或查询 Markdown 文件后,你可以在 .astro 组件中编写包含 frontmatter 数据和正文内容的动态 HTML 模板。

src/posts/great-post.md
---
title: '有史以来最好的文章'
author: 'Ben'
---
这是我的 _很棒_ 的文章!
src/pages/my-posts.astro
---
import * as greatPost from '../posts/great-post.md';
const posts = Object.values(import.meta.glob('../posts/*.md', { eager: true }));
---
<p>{greatPost.frontmatter.title}</p>
<p>作者:{greatPost.frontmatter.author}</p>
<p>文章归档:</p>
<ul>
{posts.map(post => <li><a href={post.url}>{post.frontmatter.title}</a></li>)}
</ul>

当通过辅助函数从集合中获取数据时,Markdown 的 frontmatter 属性在 data 对象(例如 post.data.title)上可用。此外,body 包含了 Markdown 的正文内容,这部分内容是原始的、未编译的字符串类型。

请参阅完整的 集合条目类型

当使用 importimport.meta.glob() 导入 Markdown 时,以下导出的属性在你的 .astro 组件中可用:

  • file - 绝对文件路径(例如 /home/user/projects/.../file.md)。
  • url - 如果是页面,则为页面的 URL(例如 /zh-cn/guides/markdown-content)。
  • frontmatter - 包含了文件的 YAML frontmatter 中所指定的任何数据。
  • <Content /> - 返回文件完整渲染内容的组件。
  • rawContent() - 一个函数,将原始 Markdown 文档作为字符串返回。
  • compiledContent() - 一个函数,将 Markdown 文档编译为 HTML 字符串后返回。
  • getHeadings() - 一个异步函数,用于返回文件中所有标题(<h1><h6>)的数组,类型为:{ depth: number; slug: string; text: string }[]。每个标题的 slug 都对应了给定标题生成的 ID,可用于锚点链接。

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

Astro.props = {
file: "/home/user/projects/.../file.md",
url: "/en/guides/markdown-content/",
frontmatter: {
/** 从博客文章中获取的 Frontmatter */
title: "Astro 0.18 Release",
date: "Tuesday, July 27 2021",
author: "Matthew Phillips",
description: "Astro 0.18 is our biggest release since Astro launch.",
},
getHeadings: () => [
{"depth": 1, "text": "Astro 0.18 Release", "slug": "astro-018-release"},
{"depth": 2, "text": "Responsive partial hydration", "slug": "responsive-partial-hydration"}
/* ... */
],
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>",
}

<Content /> 组件可通过从 Markdown 文件导入 Content 来使用。此组件返回文件的完整正文内容,并渲染为 HTML。你可以选择将 Content 重命名为你喜欢的任何组件名称。

同样,你也可以通过渲染 <Content /> 组件来 渲染 Markdown 集合条目的 HTML 内容

src/pages/content.astro
---
// 导入语句
import {Content as PromoBanner} from '../components/promoBanner.md';
// 集合查询
import { getEntry, render } from 'astro:content';
const product = await getEntry('products', 'shirt');
const { Content } = await render();
---
<h2>今日促销</h2>
<PromoBanner />
<p>促销截止至:{product.data.saleEndDate.toDateString()}</p>
<Content />

在 Markdown 中编写标题会自动为你提供锚点链接,以便你可以直接跳转到页面的某些部分。

src/pages/page-1.md
---
title: 我的文章目录
---
## 简介
当我使用 Markdown 时,我可以在同一个页面内链接到 [我的结论](#结论) 部分。
## 结论
我可以通过在浏览器访问 `https://example.com/page-1/#简介` 以直接导航到简介部分。

Astro 基于 github-slugger 生成标题 id。你可以在 github-slugger 文档 中找到更多示例。

Astro 将 id 属性注入到 Markdown 和 MDX 文件中的所有标题元素(<h1><h6>)中,并提供 getHeadings() 工具函数来检索 Markdown 导出属性 中的这些 ID。

你可以通过添加注入 id 属性的 rehype 插件(例如 rehype-slug)来自定义这些标题 ID。你的自定义 ID 将替代 Astro 的默认 ID,反映在 HTML 输出和 getHeadings() 返回的数组中。

默认情况下,Astro 会在你的 rehype 插件运行后注入 id 属性。但如果其中一个自定义 rehype 插件需要访问 Astro 注入的 ID,你可以直接导入并使用 Astro 的 rehypeHeadingIds 插件。确保在任何依赖它的插件之前添加 rehypeHeadingIds

astro.config.mjs
import { defineConfig } from 'astro/config';
import { rehypeHeadingIds } from '@astrojs/markdown-remark';
import { otherPluginThatReliesOnHeadingIDs } from 'some/plugin/source';
export default defineConfig({
markdown: {
rehypePlugins: [
rehypeHeadingIds,
otherPluginThatReliesOnHeadingIDs,
],
},
});

Astro 中的 Markdown 支持由 remark 提供,remark 是一个强大的解析和处理工具,拥有一个活跃的生态系统。目前不支持其他 Markdown 解析器,如 Pandoc 和 markdown-it。

Astro 默认应用 GitHub 风格的 MarkdownSmartyPants 插件。这带来了一些便利,例如从文本生成可点击的链接,并格式化引用和 em-dashes

你可以在 astro.config.mjs 中自定义 remark 解析 Markdown 的方式。请参阅完整的 Markdown 配置选项列表。

添加 remark 和 rehype 插件

段落标题 添加 remark 和 rehype 插件

Astro 支持添加第三方 remarkrehype 插件来解析 Markdown。这些插件允许你扩展你的 Markdown,以获得新的功能,例如 自动生成目录应用可访问的表情符号标签,以及为你的 Markdown 添加样式

我们鼓励你浏览 awesome-remarkawesome-rehype 来查看流行的插件!请参阅每个插件自己的 README 以获取特定的安装说明。

这个例子将 remark-tocrehype-accessible-emojis 应用于 Markdown 文件:

astro.config.mjs
import { defineConfig } from 'astro/config';
import remarkToc from 'remark-toc';
import { rehypeAccessibleEmojis } from 'rehype-accessible-emojis';
export default defineConfig({
markdown: {
remarkPlugins: [ [remarkToc, { heading: 'toc', maxDepth: 3 } ] ],
rehypePlugins: [rehypeAccessibleEmojis],
},
});

为了自定义插件,请在嵌套数组中提供选项对象。

下面的示例将 标题选项添加到 remarkToc 插件 以更改目录的放置位置,并将 behavior 选项添加到 rehype-autolink-headings 插件以便在标题文本之后添加锚标记。

astro.config.mjs
import remarkToc from 'remark-toc';
import rehypeSlug from 'rehype-slug';
import rehypeAutolinkHeadings from 'rehype-autolink-headings';
export default {
markdown: {
remarkPlugins: [ [remarkToc, { heading: "contents"} ] ],
rehypePlugins: [rehypeSlug, [rehypeAutolinkHeadings, { behavior: 'append' }]],
},
}

以编程方式修改 frontmatter

段落标题 以编程方式修改 frontmatter

你可以通过使用 remark 或 rehype 插件 为所有 Markdown 和 MDX 文件添加 frontmatter 属性。

  1. 从插件的 file 参数中将 customProperty 附加到 data.astro.frontmatter 属性:

    example-remark-plugin.mjs
    export function exampleRemarkPlugin() {
    // 所有 remark 和 rehype 插件都返回一个单独的函数
    return function (tree, file) {
    file.data.astro.frontmatter.customProperty = 'Generated property';
    }
    }
  2. 将此插件应用于你的 markdownmdx 集成配置:

    astro.config.mjs
    import { defineConfig } from 'astro/config';
    import { exampleRemarkPlugin } from './example-remark-plugin.mjs';
    export default defineConfig({
    markdown: {
    remarkPlugins: [exampleRemarkPlugin]
    },
    });

    或者

    astro.config.mjs
    import { defineConfig } from 'astro/config';
    import { exampleRemarkPlugin } from './example-remark-plugin.mjs';
    export default defineConfig({
    integrations: [
    mdx({
    remarkPlugins: [exampleRemarkPlugin],
    }),
    ],
    });

现在,每个 Markdown 或 MDX 文件都会在其 frontmatter 中有 customProperty,使其在 导入你的 markdown 时以及从 布局中的 Astro.props.frontmatter 属性 中可用。

Related recipe: 添加阅读时间

从 MDX 扩展 Markdown 配置

段落标题 从 MDX 扩展 Markdown 配置

Astro 的 MDX 集成默认情况下会扩展你的项目的现有 Markdown 配置。要覆盖单个选项,你可以在 MDX 配置中指定它们的等效项。

下面的示例禁用了 GitHub-Flavored Markdown,并为 MDX 文件应用了不同的 remark 插件集:

astro.config.mjs
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
export default defineConfig({
markdown: {
syntaxHighlight: 'prism',
remarkPlugins: [remarkPlugin1],
gfm: true,
},
integrations: [
mdx({
// `syntaxHighlight` 继承自 Markdown
// Markdown `remarkPlugins` 被忽略
// 仅应用 `remarkPlugin2`
remarkPlugins: [remarkPlugin2],
// `gfm` 覆盖为 `false`
gfm: false,
})
]
});

要避免从 MDX 扩展你的 Markdown 配置,请将 extendMarkdownConfig 选项 (默认开启) 设置为 false:

astro.config.mjs
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
export default defineConfig({
markdown: {
remarkPlugins: [remarkPlugin],
},
integrations: [
mdx({
// Markdown 配置现在被忽略
extendMarkdownConfig: false,
// 没有 `remarkPlugins` 应用
})
]
});

Astro 将 /src/pages/ 目录 内的任何受支持的文件视为页面,包括 .md 和其他 Markdown 文件类型。

将文件放入此目录或任何子目录中,将使用文件的路径名自动构建页面路由,并显示渲染为 HTML 的 Markdown 内容。

src/pages/page-1.md
---
title: 你好,世界
---
# 嗨!
这个 Markdown 文件在 `your-domain.com/page-1/` 创建了一个页面
也许没有什么样式装点,但 Markdown 还支持这个:
- **加粗**_斜体。_
- 列表项
- [链接](https://astro.build)
- <p>HTML 元素</p>
- 还有更多!

为了帮助扩展 Markdown 页面的有限功能,Astro 提供了一个特殊的 frontmatter layout 属性,它是 Astro Markdown 布局组件 的相对路径。如果你的 Markdown 文件位于 src/pages/ 中,请创建一个布局组件并将其添加到此布局属性中,来为你的 Markdown 内容提供一个页面外壳。

src/pages/posts/post-1.md
---
layout: ../../layouts/BlogPostLayout.astro
title: Astro 简介
author: Himanshu
description: 发现 Astro 的魅力之所在!
---
这是一篇使用 Markdown 编写的文章。

此布局组件是一个常规 Astro 组件,具有通过 Astro.props 为你的 Astro 模板 自动提供详细的可用属性 的功能。例如,你可以通过 Astro.props.frontmatter 访问 Markdown 文件的 frontmatter 属性:

src/layouts/BlogPostLayout.astro
---
const {frontmatter} = Astro.props;
---
<html>
<!-- ... -->
<h1>{frontmatter.title}</h1>
<h2>文章作者:{frontmatter.author}</h2>
<p>{frontmatter.description}</p>
<slot /> <!-- Markdown 内容被注入到这里 -->
<!-- ... -->
</html>

你也可以在布局组件中 为你的 Markdown 设置样式

阅读更多关于 Markdown 布局 的内容。

Astro 不包括对 实验性内容集合 之外的远程 Markdown 的内置支持!

要直接获取远程的 Markdown 并将其渲染为 HTML,你需要从 NPM 安装并配置你自己的 Markdown 解析器。这 不会 继承你配置的任何 Astro 内置 Markdown 设置。

在你的项目中实现此功能之前,请确保你了解这些限制,并考虑使用内容集合加载器来代替获取远程 Markdown。

src/pages/remote-example.astro
---
// 示例:从一个远程的 API 接口请求 Markdown
// 并在运行时将其渲染为 HTML
// 使用了 "marked" 库 (https://github.com/markedjs/marked)
import { marked } from 'marked';
const response = await fetch('https://raw.githubusercontent.com/wiki/adam-p/markdown-here/Markdown-Cheatsheet.md');
const markdown = await response.text();
const content = marked.parse(markdown);
---
<article set:html={content} />
Contribute

What’s on your mind?

Create GitHub Issue

Quickest way to alert our team of a problem.

Community