跳到主要内容

MDX 和 React

Docusaurus 内置支持 MDX ,允许你在 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 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.

I can write Markdown alongside my JSX!

MDX 是 JSX

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

/* Instead of this: */
<span style="background-color: red">Foo</span>
/* Use this: */
<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 green</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 组件实现的记录。

如果你 swizzle 这个组件,你会发现所有已实现的标签,并且你可以通过 swizzle 相应的子组件(例如 @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!

注意

我们故意使用 大写 标签名称,例如 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 组件(查看 playground )。

一些有效的 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 前置 matter
  • .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>

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:作为字符串键和值记录的前置 matter;

  • toc:目录,作为标题的树。另请参阅 内联 TOC ,了解更具体的用例。

  • contentTitle:Markdown 标题,即 Markdown 文本中的第一个 h1 标题。如果没有(例如,在 front matter 中指定的标题),则为 undefined

import TOCInline from '@theme/TOCInline';
import CodeBlock from '@theme/CodeBlock';

此页面的目录,已序列化:

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

此页面的前置 matter:

<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
}
]

此页面的前置 matter:

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

此页面的标题为:MDX 和 React