跳到主要内容

1、MDX 和 React

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

image-20240912075950348


自己测试效果:

image-20240912121528738

image-20240912121550290

MDX 是 JSX

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

/* Instead of this: */
<span style="background-color: red">Foo</span>

/* Use this: */
<span style={{backgroundColor: 'red'}}>Foo</span>

导入组件

你还可以导入在其他文件中定义的自己的组件或通过 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 时免于更新导入路径。

虽然在 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 文件提供。与 @theme/ 别名下的大多数其他导出不同,它本身不是一个 React 组件:它是从像 Highlight 这样的标签名称到它们的 React 组件实现的记录。

如果你对该组件进行 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>,而无需编写 import 语句:

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

http://localhost:3000

image-20240912122308222

注意

我们故意使用大写的标签名称,例如 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 支持:

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

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

导入代码片段

你不仅可以导入包含组件定义的文件,还可以将任何代码文件作为原始文本导入,然后将其插入代码块中,这要归功于 Webpack 原始加载器。为了使用 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>
);
}

image-20240913124153540

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

信息

注意

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

警告

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

导入 Markdown

你可以使用 Markdown 文件作为组件并将它们导入到其他地方,无论是在 Markdown 文件中还是在 React 页面中。

按照惯例,使用 _ 文件名前缀不会创建任何文档页面,并且意味着 Markdown 文件是 "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

image-20240913124344127

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

可用导出

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

  • frontMatter:前面的内容作为字符串键和值的记录;
  • 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

image-20240913124527514

image-20240913124540117