Skip to main content
Version: Canary 🚧

MDX 和 React

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

查看MDX文档,了解你可以用MDX做哪些酷炫的事情。

Debugging MDX

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

使用MDX playground来调试它们,并确保您的语法是有效的。

info

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 green</Highlight> and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors.

I can write **Markdown** alongside my _JSX_!

注意它如何渲染来自你的React组件的标记和Markdown语法:

http://localhost:3000
Docusaurus green and Facebook blue are my favorite colors.

我可以写Markdown和我的JSX一起!

MDX is JSX

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

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

导入组件

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

<!-- Docusaurus theme component -->
import TOCInline from '@theme/TOCInline';
<!-- External component -->
import Button from '@mui/material/Button';
<!-- Custom component -->
import BrowserWindow from '@site/src/components/BrowserWindow';
tip

@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 green</Highlight>
tip

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

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组件实现的记录。

如果你swizzle这个组件,你会发现所有已经实现的标签,并且你可以通过swizzle相应的子组件来进一步自定义我们的实现,比如@theme/MDXComponents/Code(用于渲染Markdown代码块)。

如果你想注册额外的标签名称(如上面的标签),你应该考虑包装@theme/MDXComponents,这样你就不需要维护所有现有的映射。由于swizzle CLI目前还不允许包装非组件文件,你应该手动创建包装器:

src/theme/MDXComponents.js
import React from 'react';
// Import the original mapper
import MDXComponents from '@theme-original/MDXComponents';
import Highlight from '@site/src/components/Highlight';

export default {
// Re-use the default mapping
...MDXComponents,
// Map the "<Highlight>" tag to our Highlight component
// `Highlight` will receive all props that were passed to `<Highlight>` in MDX
Highlight,
};

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

I can conveniently use <Highlight color="#25c2a0">Docusaurus green</Highlight> everywhere!
http://localhost:3000

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

warning

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

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

warning

此功能由一个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 组件,因此它更加严格(查看 playground)。

一些有效的CommonMark功能在MDX中无法使用(更多信息),特别是:

  • 缩进代码块:使用三重反引号代替
  • 自动链接 (): 使用常规链接语法代替 ([http://localhost:3000](http://localhost:3000))
  • HTML语法 (

    ): 使用JSX代替 (

    )
  • 未转义的 {<:使用 \ 进行转义(\{\<
Experimental CommonMark support

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>
);
}

查看在JSX中使用代码块以获取有关组件的更多详细信息。

note

你必须使用而不是Markdown的三重反引号```,因为后者会原样输出其内容,但你希望在这里插入导入的文本。

warning

此功能是实验性的,未来可能会发生破坏性的API更改。

导入Markdown

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

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

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

This is text some content from `_markdown-partial-example.mdx`.
someOtherDoc.mdx
import PartialExample from './_markdown-partial-example.mdx';

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

这是来自_markdown-partial-example.md的一些内容。

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

可用导出

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

  • frontMatter: 作为字符串键和值记录的前言部分;
  • toc: 目录,作为标题的树形结构。另请参阅 Inline TOC 以获取更具体的用例。
  • contentTitle: Markdown 标题,即 Markdown 文本中的第一个 h1 标题。如果没有(例如在 front matter 中指定了标题),则为 undefined
import TOCInline from '@theme/TOCInline';
import CodeBlock from '@theme/CodeBlock';

The table of contents for this page, serialized:

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

The front matter of this page:

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

<p>The title of this page is: <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