跳到主要内容

MDX 和 React

Docusaurus 内置支持 MDX,允许您在 Markdown 文件中编写 JSX 并将其渲染为 React 组件。

查看 MDX 文档,了解您可以用 MDX 做些什么有趣的事情。

调试 MDX

MDX 格式非常严格,您可能会遇到编译错误。

使用 MDX 在线编辑器 来调试并确保您的语法有效。

信息

最流行的格式化工具 Prettier 仅支持旧版 MDX v1。如果您得到意外的格式化结果,可以在有问题的区域前添加 {/* prettier-ignore */},或将 *.mdx 添加到 .prettierignore,直到 Prettier 对 MDX v3 有适当的支持。MDX 的主要作者之一推荐使用 remark-cliremark-mdx

导出组件

要在 MDX 文件中定义任何自定义组件,您必须导出它:只有以 export 开头的段落才会被解析为组件而不是普通文本。

export const Highlight = ({children, color}) => (
<span
style={{
backgroundColor: color,
borderRadius: '2px',
color: '#fff',
padding: '0.2rem',
}}>
{children}
</span>
);

<Highlight color="#25c2a0">Docusaurus 绿色</Highlight><Highlight color="#1877F2">Facebook 蓝色</Highlight> 是我最喜欢的颜色。

我可以在 **Markdown** 旁边编写 _JSX_!

注意它如何同时渲染 React 组件的标记和 Markdown 语法:

http://localhost:3000
Docusaurus 绿色 Facebook 蓝色 是我最喜欢的颜色。

我可以在 Markdown 旁边编写 JSX

MDX 是 JSX

由于所有文档文件都使用 MDX 解析,任何看起来像 HTML 的内容实际上都是 JSX。因此,如果您需要内联样式一个组件,请遵循 JSX 风格并提供样式对象。

/* 不要这样写: */
<span style="background-color: red">Foo</span>
/* 而要这样写: */
<span style={{backgroundColor: 'red'}}>Foo</span>

导入组件

您还可以导入在其他文件中定义的自己的组件或通过 npm 安装的第三方组件。

<!-- Docusaurus 主题组件 -->
import TOCInline from '@theme/TOCInline';
<!-- 外部组件 -->
import Button from '@mui/material/Button';
<!-- 自定义组件 -->
import BrowserWindow from '@site/src/components/BrowserWindow';
提示

@site 别名指向您网站的目录,通常是 docusaurus.config.js 文件所在的位置。使用别名而不是相对路径('../../src/components/BrowserWindow')可以在移动文件或版本化文档翻译时避免更新导入路径。

虽然在 Markdown 中声明组件对于简单情况非常方便,但当组件涉及复杂的 JS 逻辑时,它会变得难以维护,因为编辑器支持有限,解析错误风险高,且可重用性低。对于复杂的组件,请使用单独的 .js 文件:

src/components/Highlight.js
import React from 'react';

export default function Highlight({children, color}) {
return (
<span
style={{
backgroundColor: color,
borderRadius: '2px',
color: '#fff',
padding: '0.2rem',
}}>
{children}
</span>
);
}
markdown-file.mdx
import Highlight from '@site/src/components/Highlight';

<Highlight color="#25c2a0">Docusaurus 绿色</Highlight>
提示

如果您在许多文件中使用相同的组件,则不需要在每个地方都导入它 - 考虑将其添加到全局作用域。请参见下文

MDX 组件作用域

除了导入组件导出组件之外,在 MDX 中使用组件的第三种方式是将其注册到全局作用域,这将使其自动在每个 MDX 文件中可用,无需任何导入语句。

例如,给定这个 MDX 文件:

- a
- list!

And some <Highlight>custom markup</Highlight>...

它将被编译为包含 ullipHighlight 元素的 React 组件。Highlight 不是原生 HTML 元素:您需要为其提供自己的 React 组件实现。

在 Docusaurus 中,MDX 组件作用域由 @theme/MDXComponents 文件提供。它不是一个 React 组件,与 @theme/ 别名下的大多数其他导出不同:它是从标签名(如 Highlight)到其 React 组件实现的记录。

如果您交换此组件,您将找到所有已实现的标签,并可以通过交换相应的子组件(如 @theme/MDXComponents/Code,用于渲染 Markdown 代码块)来进一步自定义我们的实现。

如果您想注册额外的标签名(如上面的 <Highlight> 标签),您应该考虑包装 @theme/MDXComponents,这样就不必维护所有现有的映射。由于交换 CLI 尚不允许包装非组件文件,因此您应该手动创建包装器:

src/theme/MDXComponents.js
import React from 'react';
// 导入原始映射器
import MDXComponents from '@theme-original/MDXComponents';
import Highlight from '@site/src/components/Highlight';

export default {
// 重用默认映射
...MDXComponents,
// 将 "<Highlight>" 标签映射到我们的 Highlight 组件
// `Highlight` 将接收在 MDX 中传递给 `<Highlight>` 的所有 props
Highlight,
};

现在,您可以在每个页面自由使用 <Highlight>,无需编写导入语句:

我可以方便地在任何地方使用 <Highlight color="#25c2a0">Docusaurus 绿色</Highlight>
http://localhost:3000

我可以方便地在任何地方使用 Docusaurus 绿色

注意

我们特意使用大写标签名,如 Highlight

从 MDX v3+(Docusaurus v3+)开始,小写标签名始终渲染为原生 HTML 元素,并且不会使用您提供的任何组件映射。

注意

此功能由 MDXProvider 提供支持。如果您在 React 页面中导入 Markdown,则必须通过 MDXContent 主题组件自行提供此提供程序。

src/pages/index.js
import React from 'react';
import FeatureDisplay from './_featureDisplay.mdx';
import MDXContent from '@theme/MDXContent';

export default function LandingPage() {
return (
<div>
<MDXContent>
<FeatureDisplay />
</MDXContent>
</div>
);
}

如果不用 MDXContent 包装导入的 MDX,全局作用域将不可用。

Markdown 和 JSX 互操作性

Docusaurus v3 使用 MDX v3

MDX 语法CommonMark 大部分兼容,但更加严格,因为您的 .mdx 文件可以使用 JSX 并编译为真正的 React 组件(查看在线编辑器)。

一些有效的 CommonMark 特性在 MDX 中不起作用(更多信息),特别是:

  • 缩进代码块:改用三个反引号
  • 自动链接(<http://localhost:3000>):改用常规链接语法([http://localhost:3000](http://localhost:3000)
  • HTML 语法(<p style="color: red;">):改用 JSX(<p style={{color: 'red'}}>
  • 未转义的 {<:使用 \ 转义(\{\<
实验性 CommonMark 支持

Docusaurus v3 可以通过以下选项选择不太严格的标准 CommonMark 支持:

  • mdx.format: md 前置元数据
  • .md 文件扩展名与 siteConfig.markdown.format: "detect" 配置结合

此功能是实验性的,目前有一些限制

导入代码片段

您不仅可以导入包含组件定义的文件,还可以将任何代码文件作为原始文本导入,然后将其插入代码块,这要感谢 Webpack raw-loader。要使用 raw-loader,您首先需要在项目中安装它:

npm install --save raw-loader

现在您可以按原样导入另一个文件中的代码片段:

myMarkdownFile.mdx
import CodeBlock from '@theme/CodeBlock';
import MyComponentSource from '!!raw-loader!./myComponent';

<CodeBlock language="jsx">{MyComponentSource}</CodeBlock>
http://localhost:3000
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import React, {useState} from 'react';

export default function MyComponent() {
const [bool, setBool] = useState(false);
return (
<div>
<p>MyComponent rendered !</p>
<p>bool={bool ? 'true' : 'false'}</p>
<p>
<button onClick={() => setBool((b) => !b)}>toggle bool</button>
</p>
</div>
);
}

有关 <CodeBlock> 组件的更多详细信息,请参见 在 JSX 中使用代码块

备注

您必须使用 <CodeBlock>,而不是 Markdown 三个反引号 ```,因为后者会原样输出其内容,但您希望在此处插入导入的文本。

注意

此功能是实验性的,将来可能会有破坏性的 API 更改。

导入 Markdown

您可以将 Markdown 文件用作组件,并在其他地方导入它们,无论是在 Markdown 文件还是 React 页面中。每个 MDX 文件默认导出其页面内容作为 React 组件。在 import 语句中,您可以使用任何名称默认导入此组件,但必须遵循 React 的命名规则进行大写。

按照惯例,使用 _ 文件名前缀将不会创建任何文档页面,并且意味着 Markdown 文件是一个**"部分"**,供其他文件导入。

_markdown-partial-example.mdx
<span>Hello {props.name}</span>

这是来自 `_markdown-partial-example.mdx` 的一些文本内容。
someOtherDoc.mdx
import PartialExample from './_markdown-partial-example.mdx';

<PartialExample name="Sebastien" />
http://localhost:3000
Hello Sebastien

This is text some content from _markdown-partial-example.md.

这样,您可以在多个页面之间重用内容并避免重复材料。

可用的导出

在 MDX 页面中,以下变量可作为全局变量使用:

  • frontMatter:前置元数据作为字符串键和值的记录;
  • toc:目录,作为标题树。另请参见内联目录以获取更具体的用例。
  • contentTitle:Markdown 标题,即 Markdown 文本中的第一个 h1 标题。如果没有(例如在前置元数据中指定标题),则为 undefined
import TOCInline from '@theme/TOCInline';
import CodeBlock from '@theme/CodeBlock';

此页面的目录,序列化:

<CodeBlock className="language-json">{JSON.stringify(toc, null, 2)}</CodeBlock>

此页面的前置元数据:

<ul>
{Object.entries(frontMatter).map(([key, value]) => <li key={key}><b>{key}</b>: {value}</li>)}
</ul>

<p>此页面的标题是:<b>{contentTitle}</b></p>
http://localhost:3000

此页面的目录,序列化:

[
{
"value": "导出组件",
"id": "exporting-components",
"level": 3
},
{
"value": "导入组件",
"id": "importing-components",
"level": 3
},
{
"value": "MDX 组件作用域",
"id": "mdx-component-scope",
"level": 3
},
{
"value": "Markdown 和 JSX 互操作性",
"id": "markdown-and-jsx-interoperability",
"level": 3
},
{
"value": "导入代码片段",
"id": "importing-code-snippets",
"level": 2
},
{
"value": "导入 Markdown",
"id": "importing-markdown",
"level": 2
},
{
"value": "可用的导出",
"id": "available-exports",
"level": 2
}
]

此页面的前置元数据:

  • id: react
  • description: 在 Docusaurus Markdown 文档中使用 React 的强大功能,感谢 MDX
  • slug: /markdown-features/react

此页面的标题是:MDX 和 React