Skip to main content
Version: 3.6.1

MDX 和 React

¥MDX and React

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

¥Docusaurus has built-in support for MDX, which allows you to write JSX within your Markdown files and render them as React components.

查看 MDX 文档,看看你可以使用 MDX 做哪些奇特的事情。

¥Check out the MDX docs to see what fancy stuff you can do with MDX.

调试 MDX

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

¥The MDX format is quite strict, and you may get compilation errors.

使用 MDX 在线运行 调试它们并确保你的语法有效。

¥Use the MDX playground to debug them and make sure your syntax is valid.

信息

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

¥Prettier, the most popular formatter, supports only the legacy MDX v1. If you get an unintentional formatting result, you may want to add {/* prettier-ignore */} before the problematic area, or add *.mdx to your .prettierignore, until Prettier has proper support for MDX v3. One of the main authors of MDX recommends remark-cli with remark-mdx.

导出组件

¥Exporting components

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

¥To define any custom component within an MDX file, you have to export it: only paragraphs that start with export will be parsed as components instead of prose.

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 语法:

¥Notice how it renders both the markup from your React component and the Markdown syntax:

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

I can write Markdown alongside my JSX!

MDX 是 JSX

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

¥Since all doc files are parsed using MDX, anything that looks like HTML is actually JSX. Therefore, if you need to inline-style a component, follow JSX flavor and provide style objects.

/* Instead of this: */
<span style="background-color: red">Foo</span>
/* Use this: */
<span style={{backgroundColor: 'red'}}>Foo</span>

导入组件

¥Importing components

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

¥You can also import your own components defined in other files or third-party components installed via 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';
提示

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

¥The @site alias points to your website's directory, usually where the docusaurus.config.js file is. Using an alias instead of relative paths ('../../src/components/BrowserWindow') saves you from updating import paths when moving files around, or when versioning docs and translating.

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

¥While declaring components within Markdown is very convenient for simple cases, it becomes hard to maintain because of limited editor support, risks of parsing errors, and low reusability. Use a separate .js file when your component involves complex JS logic:

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>
提示

如果你在多个文件中使用相同的组件,则无需将其导入到任何地方 - 考虑将其添加到全局范围。见下文

¥If you use the same component across a lot of files, you don't need to import it everywhere—consider adding it to the global scope. See below

MDX 组件范围

¥MDX component scope

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

¥Apart from importing a component and exporting a component, a third way to use a component in MDX is to register it to the global scope, which will make it automatically available in every MDX file, without any import statements.

例如,给定此 MDX 文件:

¥For example, given this MDX file:

- a
- list!

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

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

¥It will be compiled to a React component containing ul, li, p, and Highlight elements. Highlight is not a native html element: you need to provide your own React component implementation for it.

在 Docusaurus 中,MDX 组件范围由 @theme/MDXComponents 文件提供。与 @theme/ 别名下的大多数其他导出不同,它本身不是一个 React 组件:它是从像 Highlight 这样的标签名称到它们的 React 组件实现的记录。

¥In Docusaurus, the MDX component scope is provided by the @theme/MDXComponents file. It's not a React component, per se, unlike most other exports under the @theme/ alias: it is a record from tag names like Highlight to their React component implementations.

如果你对该组件进行 swizzle,你将找到已实现的所有标签,并且你可以通过调整相应的子组件来进一步自定义我们的实现,例如 @theme/MDXComponents/Code(用于渲染 Markdown 代码块)。

¥If you swizzle this component, you will find all tags that have been implemented, and you can further customize our implementation by swizzling the respective sub-component, like @theme/MDXComponents/Code (which is used to render Markdown code blocks).

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

¥If you want to register extra tag names (like the <Highlight> tag above), you should consider wrapping @theme/MDXComponents, so you don't have to maintain all the existing mappings. Since the swizzle CLI doesn't allow wrapping non-component files yet, you should manually create the wrapper:

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>,而无需编写 import 语句:

¥And now, you can freely use <Highlight> in every page, without writing the import statement:

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

I can conveniently use Docusaurus green everywhere!

警告

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

¥We use upper-case tag names like Highlight on purpose.

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

¥From MDX v3+ onward (Docusaurus v3+), lower-case tag names are always rendered as native html elements, and will not use any component mapping you provide.

警告

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

¥This feature is powered by an MDXProvider. If you are importing Markdown in a React page, you have to supply this provider yourself through the MDXContent theme component.

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,则全局作用域将不可用。

¥If you don't wrap your imported MDX with MDXContent, the global scope will not be available.

Markdown 和 JSX 互操作性

¥Markdown and JSX interoperability

Docusaurus v3 使用的是 MDX v3

¥Docusaurus v3 is using MDX v3.

MDX 语法 大部分与 CommonMark 兼容,但更严格,因为你的 .mdx 文件可以使用 JSX 并编译成真正的 React 组件(检查 playground)。

¥The MDX syntax is mostly compatible with CommonMark, but is much stricter because your .mdx files can use JSX and are compiled into real React components (check the playground).

一些有效的 CommonMark 功能不适用于 MDX (更多信息),特别是:

¥Some valid CommonMark features won't work with MDX (more info), notably:

  • 缩进代码块:使用三个反引号代替

    ¥Indented code blocks: use triple backticks instead

  • 自动链接 (http://localhost:3000):使用常规链接语法代替 ([http://localhost:3000](http://localhost:3000))

    ¥Autolinks (http://localhost:3000): use regular link syntax instead ([http://localhost:3000](http://localhost:3000))

  • HTML 语法 (<p style="color: red;">):使用 JSX 代替 (<p style={{color: 'red'}}>)

    ¥HTML syntax (<p style="color: red;">): use JSX instead (<p style={{color: 'red'}}>)

  • 未转义的 {<:用 \ 来转义它们(\{\<

    ¥Unescaped { and <: escape them with \ instead (\{ and \<)

实验性 CommonMark 支持

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

¥Docusaurus v3 makes it possible to opt-in for a less strict, standard CommonMark support with the following options:

  • mdx.format: md 前言

    ¥The mdx.format: md front matter

  • .md 文件扩展名与 siteConfig.markdown.format: "detect" 配置相结合

    ¥The .md file extension combined with the siteConfig.markdown.format: "detect" configuration

这个功能是实验性的,目前有几个 limitations

¥This feature is experimental and currently has a few limitations.

导入代码片段

¥Importing code snippets

你不仅可以导入包含组件定义的文件,还可以将任何代码文件作为原始文本导入,然后将其插入代码块中,这要归功于 Webpack 原始加载器。为了使用 raw-loader,你首先需要将其安装到你的项目中:

¥You can not only import a file containing a component definition, but also import any code file as raw text, and then insert it in a code block, thanks to Webpack raw-loader. In order to use raw-loader, you first need to install it in your project:

npm install --save raw-loader

现在你可以从另一个文件中导入代码片段,如下所示:

¥Now you can import code snippets from another file as it is:

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 中使用代码块

¥See using code blocks in JSX for more details of the <CodeBlock> component.

注意

你必须使用 <CodeBlock> 而不是 Markdown 三重反引号 `````,因为后者将按原样发送其任何内容,但你想在此处插入导入的文本。

¥You have to use <CodeBlock> rather than the Markdown triple-backtick ```, because the latter will ship out any of its content as-is, but you want to interpolate the imported text here.

警告

此功能是实验性的,将来可能会发生重大 API 更改。

¥This feature is experimental and might be subject to breaking API changes in the future.

导入 Markdown

¥Importing Markdown

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

¥You can use Markdown files as components and import them elsewhere, either in Markdown files or in React pages. Each MDX file default-exports its page content as a React component. In the import statement, you can default-import this component with any name, but it must be capitalized following React's naming rules.

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

¥By convention, using the _ filename prefix will not create any doc page and means the Markdown file is a "partial", to be imported by other files.

_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 的一些内容。

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

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

¥This way, you can reuse content among multiple pages and avoid duplicating materials.

可用导出

¥Available exports

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

¥Within the MDX page, the following variables are available as globals:

  • frontMatter:前面的内容作为字符串键和值的记录;

    ¥frontMatter: the front matter as a record of string keys and values;

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

    ¥toc: the table of contents, as a tree of headings. See also Inline TOC for a more concrete use-case.

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

    ¥contentTitle: the Markdown title, which is the first h1 heading in the Markdown text. It's undefined if there isn't one (e.g. title specified in the front matter).

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 {#mdx-and-react}