Skip to navigation

什么是 MDX?

本文介绍什么是 MDX 格式。 它展示了如何在 MDX 中使用 ESM 中的 markdown、JSX、JavaScript 表达式以及 importexport 语句。 有关如何将 MDX 集成到你的项目中的详细信息,请参阅 § 入门

内容

先决条件

要编写和使用 MDX,你应该熟悉 Markdown(请参阅此 备忘单和教程 获取帮助)和 JavaScript(特别是 JSX)。

组件时代的 Markdown

MDX 允许你在 Markdown 内容中使用 JSX。 你可以导入交互式图表或警报等组件,并将它们嵌入到你的内容中。 这使得使用组件编写长篇内容变得非常有趣。 🚀

更实际的是,MDX 可以解释为一种将 markdown 与 JSX 结合在一起的格式,如下所示:

MDX
# Hello, world!

<div className="note">
  > Some notable things in a block quote!

</div>

标题和块引用是 markdown,而那些类似 HTML 的标签是 JSX。 对于强调或标题等常见内容,Markdown 通常感觉比 HTML 或 JSX 更自然。 JSX 是 JavaScript 的扩展,看起来像 HTML,但可以方便地使用组件(可重用的东西)。

此示例在 <div> 上使用 className。 那是因为它是为 React 编写的,而 React 期望类是这样的。 其他框架(例如 Vue 和 Preact)期望类的定义不同,因此请注意,根据所使用的工具,JSX 的编写方式存在一些差异。

MDX 还支持 JavaScript 的其他一些功能: 大括号 ({1 + 1}) 和 ESM(importexport)中的表达式。

MDX 语法

注意: 你不必对 @mdx-js/* 包使用此语法。 或者一直使用它。 如果你使用打包器集成,则可以通过文件扩展名(.mdx.md)在 MDX 和 Markdown 之间进行更改。 或者,可以使用 options.format

MDX 语法将 markdown 与 JSX 结合起来。 这给了我们一些类似于文学编程的东西。 它还为我们提供了两种语言的奇怪组合: markdown 是 空格敏感forgiving(你输入的内容可能不完全有效,但不会崩溃),而 JavaScript 是 空格不敏感unforgiving(它确实会因拼写错误而崩溃)。

奇怪的是,我们非常喜欢它们的结合方式!

Markdown

对于强调或标题等常见内容,Markdown 通常感觉比 HTML 或 JSX 更自然。 Markdown 通常看起来更符合预期并且更简洁。 而不是以下 HTML:

HTML
<blockquote>
  <p>A blockquote with <em>some</em> emphasis.</p>
</blockquote>

你可以在 markdown (或 MDX)中编写等效内容,如下所示:

Markdown
> A blockquote with *some* emphasis.

MDX 默认支持标准 Markdown (CommonMark):

Markdown
# Heading (rank 1)
## Heading 2
### 3
#### 4
##### 5
###### 6

> Block quote

* Unordered
* List

1. Ordered
2. List

A paragraph, introducing a thematic break:

---

```js
some.code()
```

a [link](https://example.com), an ![image](./image.png), some *emphasis*,
something **strong**, and finally a little `code()`.

非标准 Markdown 功能(例如 GFM、frontmatter、数学、语法高亮)可以通过插件启用(参见 ¶ 使用插件)。

一些 Markdown 功能在 MDX 中不起作用:

  • 缩进代码在 MDX 中不起作用:
    MDX
        console.log(1) // this is a paragraph in MDX!
    
    这样做的原因是这样你可以很好地缩进你的组件:
    MDX
    <main>
      <article>
        # Hello!
      </article>
    </main>
    
  • 自动链接在 MDX 中不起作用。 原因是它们与 JSX 无法区分(例如:<svg:rect>),而我们更喜欢明确的。 如果你需要链接,请使用完整链接: [描述性文本](https://and-the-link-here.com)
  • HTML 语法在 MDX 中不起作用,因为它已被 JSX(<img><img />)取代。 你可以使用大括号中的 JavaScript 注释来代替 HTML 注释: {/* comment! */}
  • 未转义的左尖括号/小于 (<) 和左大括号 ({) 必须转义: \<\{(或使用表达式:{'<'}{'{'}

有关 MDX 与 Markdown 有何不同的更多信息,请参见 记录在这里

JSX

JSX 是 JavaScript 的扩展,看起来像 HTML,但可以方便地使用组件(可重用的东西)。 JSX 通常与 React、Preact 或 Vue 等前端框架结合使用。 这些框架添加了对组件的支持,使你可以更改重复的内容,例如以下标记:

HTML
<h2>Hello, Venus!</h2>
<h2>Hello, Mars!</h2>

…像这样的 JSX(或 MDX):

MDX
<Welcome name="Venus" />
<Welcome name="Mars" />

JSX 对 components 有好处。 它使重复的事情变得更加清晰,并允许关注点分离。 MDX 支持 JSX 语法。 下面的内容看起来很像 HTML:

MDX
<h1>Heading!</h1>

<abbr title="HyperText Markup Language">HTML</abbr> is a lovely language.

<section>
  And here is *markdown* in **JSX**!
</section>

但正如前面提到的,你也可以使用组件。 请注意,必须定义组件。 你可以导入它们、在本地定义它们或稍后传递它们(参见 § 使用 MDX):

MDX
<MyComponent id="123" />

You can also use objects with components, such as the `thisOne` component on
the `myComponents` object: <myComponents.thisOne />

<Component
  open
  x={1}
  label={'this is a string, *not* markdown!'}
  icon={<Icon />}
/>

有一些边缘情况 MDX 与 JSX 的不同之处

表达式

MDX 还支持大括号内的 JavaScript 表达式:

MDX
Two 🍰 is: {Math.PI * 2}

表达式可以包含整个 JavaScript 程序,只要它们(封装在)计算结果为可渲染内容的表达式中即可。 你可以像这样使用 IIFE

MDX
{(function () {
  const guess = Math.random()

  if (guess > 0.66) {
    return <span style={{color: 'tomato'}}>Look at us.</span>
  }

  if (guess > 0.33) {
    return <span style={{color: 'violet'}}>Who would have guessed?!</span>
  }

  return <span style={{color: 'goldenrod'}}>Not me.</span>
})()}

表达式可以为空或仅包含注释:

MDX
{/* A comment! */}

ESM

MDX 还支持 JavaScript 中的 importexport 语句。 这些 ESM 功能可以在 MDX 中使用来定义事物:

MDX
import {External} from './some/place.js'

export const Local = props => <span style={{color: 'red'}} {...props} />

An <External>external</External> component and a <Local>local one</Local>.

ESM 也可用于非组件(数据):

MDX
import {Chart} from './chart.js'
import population from './population.js'
export const pi = 3.14

<Chart data={population} label={'Something with ' + pi} />

交织

如果文本和标签位于同一行,则可以在 JSX 中使用 markdown “inlines” 但不能使用 “blocks”:

MDX
<div># this is not a heading but *this* is emphasis
</div>

一行上的文本和标签不会生成块,因此它们也不会生成 <p>。 在不同的线路上,他们这样做:

MDX
<div>
  This is a `p`.

</div>

我们使用这个规则来区分(同一条线或不同线)。 不基于 HTML 中元素的语义。 所以你可以构建不正确的 HTML(你不应该这样做):

MDX
<h1 className="main">
  Don’t do this: it’s a `p` in an `h1`
</h1>

<h1 className="main">Do this: an `h1` with `code`</h1>

如果文本和标签位于同一行,但相应的标签位于不同行,则无法换行 “blocks”:

MDX
Welcome! <a href="about.html">

This is home of...

# The Falcons!</a>

这是因为要解析 markdown,我们首先要把它分成 “blocks”。 所以在这种情况下有两个段落和一个标题。 在第一段中留下一个开始 a 标签,并在标题中留下一个杂散的结束 a 标签。

进一步阅读

MDX 中文网 - 粤ICP备13048890号