MDX 和 React
Docusaurus 内置支持 MDX ,允许你在 Markdown 文件中编写 JSX 并将其渲染为 React 组件。
查看 MDX 文档 ,了解你可以用 MDX 做哪些有趣的事情。
MDX 格式非常严格,你可能会遇到编译错误。
使用 MDX playground 进行调试,并确保你的语法有效。
最流行的格式化工具 Prettier 仅支持旧版 MDX v1 。如果你得到意外的格式化结果,你可能需要在问题区域之前添加 {/* prettier-ignore */}
,或者将 *.mdx
添加到你的 .prettierignore
中,直到 Prettier 正确支持 MDX v3。 MDX 的主要作者之一推荐使用带有 remark-mdx
的 remark-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 语法:
I can write Markdown alongside my 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';
虽然在 Markdown 中声明组件对于简单的情况非常方便,但由于编辑器支持有限、解析错误的风险以及可重用性低,因此难以维护。如果你的组件涉及复杂的 JS 逻辑,请使用单独的 .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>
);
}
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>...
它将编译成一个包含 ul
、li
、p
和 Highlight
元素的 React 组件。Highlight
不是原生 html 元素:你需要为此提供你自己的 React 组件实现。
在 Docusaurus 中,MDX 组件作用域由 @theme/MDXComponents
文件提供。它本身并非 React 组件,这与 @theme/
别名下的大多数其他导出不同:它是一个从标签名称(如 Highlight
)到它们的 React 组件实现的记录。
如果你 swizzle 这个组件,你会发现所有已实现的标签,并且你可以通过 swizzle 相应的子组件(例如 @theme/MDXComponents/Code
(用于渲染 Markdown 代码块 ))来进一步自定义我们的实现。
如果你想注册额外的标签名称(如上面的 <Highlight>
标签),你应该考虑 包装 @theme/MDXComponents
,这样你就不必维护所有现有的映射。由于 swizzle CLI 还不允许包装非组件文件,因此你应该手动创建包装器:
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!
I can conveniently use Docusaurus green everywhere!
我们故意使用 大写 标签名称,例如 Highlight
。
从 MDX v3+ 开始(Docusaurus v3+),小写标签名称始终被渲染为原生 html 元素,并且不会使用你提供的任何组件映射。
此功能由 MDXProvider
提供支持。如果你在 React 页面中导入 Markdown,则必须通过 MDXContent
主题组件自行提供此提供程序。
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'}}>
) - 未转义的
{
和<
:改用\
转义它们(\{
和\<
)
Docusaurus v3 使得可以使用以下选项选择加入不太严格的标准 CommonMark 支持:
mdx.format: md
前置 matter.md
文件扩展名与siteConfig.markdown.format: "detect"
配置结合使用
此功能为 实验性 功能,目前有一些 限制 。
导入代码片段
你不仅可以导入包含组件定义的文件,还可以导入任何代码文件作为原始文本,然后将其插入代码块中,这要感谢 Webpack raw-loader 。为了使用 raw-loader
,你首先需要在你的项目中安装它:
- npm
- Yarn
- pnpm
npm install --save raw-loader
yarn add raw-loader
pnpm add raw-loader
现在你可以按原样导入来自另一个文件的代码片段:
import CodeBlock from '@theme/CodeBlock';
import MyComponentSource from '!!raw-loader!./myComponent';
<CodeBlock language="jsx">{MyComponentSource}</CodeBlock>
/**
* 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 文件是 “部分” 文件,由其他文件导入。
<span>Hello {props.name}</span>
This is text some content from `_markdown-partial-example.mdx`.
import PartialExample from './_markdown-partial-example.mdx';
<PartialExample name="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>
此页面的目录,已序列化:
[
{
"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