跳到主要内容
版本:Canary 🚧

MDX 和 React

Docusaurus 原生支持 MDX v2,可以直接在 Markdown 文档中编写 JSX,并把渲染为 React 组件。

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

:::提示 调试MDX

MDX格式是相当严格的,您可能会遇到编译错误。

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

:::

信息

Prettier, 最受欢迎的格式, 仅支持遗留的 MDX v1 如果您遇到意外的格式化结果,您可能需要在问题区域前添加{/* prettier-ignore */},或者将*.mdx添加到您的 .prettierignore 中,直到 Prettier 对 MDX v3 有适当的支持。 MDX的一位主要作者推荐使用带有remark-mdxremark-cli

导出组件

要在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> 是我最喜欢的颜色。

我可以把我的 _JSX_ 和 **Markdown** 写在一起!

注意它是怎么同时渲染 React 组件和 Markdown 语法的:

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

I can write Markdown alongside my 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 文件中:

- 一个
- 列表!

和一些 <Highlight>自定义标记</Highlight>……

它会被编译成一个包含 ulliphighlight 标签的 React 组件。 Highlight 不是原生的 html 元素:你需要为它提供你自己的 React 组件的实现。

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

如果你对这个组件进行自定义替换,就会发现所有已实现的标签。而且,你能够通过自定义替换相应的子组件(如 @theme/MDXComponents/Code)来进一步定制我们的实现方案,@theme/MDXComponents/Code 这个子组件是用来渲染Markdown代码块的。

如果你想注册额外的标签名(如上面的 <Highlight> 标签),应该考虑包装 @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,
};

现在,您可以在每个页面随意使用 <Highlight> 而不需要导入它:

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

I can conveniently use Docusaurus green everywhere!

警告

我们使用 大写 标签,如 高亮来达到目的。

在从 MDX v3+ 开始更高级的版本中(Docusaurus v3+),小写标签名称总是作为原生的 html 元素呈现出来的,将不会使用您提供的组件映射。

警告

这个功能由一个MDXProvider提供支持。 如果你在 React 页面中导入 Markdown 内容,你需要从主题组件中引入 MDXContent 来自行提供 Provider。

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](http://localhost:3000))
  • HTML 语法(<p style="color: red;">):使用 JSX 来代替 (<p style={{color: 'red'}}>)
  • Unescaped { and <: escape them with \ instead (\{ and \<)
实验性的 CommonMark 支持

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

  • The mdx.format: md 前言
  • .md 文件扩展与 siteConfig.markdown.format: "detect"的配置相绑定

此功能是实验性的 ,目前有几个限制

导入代码片段

除了能从文件中导入 React 组件外,你还能把文件中的代码直接导入为普通文本,并把它插入到代码块中,作为文档的代码示例进行展示。这要归功于 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 中使用代码块 来了解 <CodeBlock> 组件的详细信息。

备注

要注意的是,显示导入的代码必须使用 <CodeBlock> 组件,不能用 Markdown 的 ``` 语法,因为后者会直接输出其所有内容,但您希望在此插入导入的文本。

警告

这个功能是试验性的,未来 API 可能会有破坏性变更。

导入 Markdown

你可以把 Markdown 文档当作 React 组件,在其它 Markdown 文件或 React 页面中导入。 每个 MDX 文件默认导出其页面内容并作为React组件 在 import 语句中,您可以使用任何名称默认导入此组件,但它必须按照 React 的命名规则大写。

按照惯例,使用 _ 作为前缀的文件不会生成任何页面,而是会被作为**“片段”(partial)** 来让其它文件导入。

_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
你好 Sebastien

这是来自 _markdown-partial-example.md 的一些文本。

这样,你可以在多个文档中复用内容,避免重复编写。

可用导出

在 MDX 页面内,以下变量可作为全局变量:

  • frontMatter:Markdown 文档的前言,包含字符串键和对应的值;
  • toc:目录,作为一个标题列表。 参考 行内目录 查看更实际的用法。
  • contentTitle :Markdown 的标题,是 Markdown 正文中的第一个 h1 。 如果没有则是 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

The table of contents for this page, serialized:

[
{
"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
}
]

The front matter of this page:

  • id: react
  • description: 得益于 MDX,你可以在 Docusaurus Markdown 文档中使用 React
  • slug: /markdown-features/react

The title of this page is: MDX 和 React