Avatar

全面的 MDX 格式指南与测试文档

欢迎来到完整的 MDX 格式测试文档。本指南演示了 MDX (Markdown + JSX) 的所有主要特性,包括标准 Markdown 语法、代码块、表格、列表等。本文档既是参考资料,也是对 MDX 渲染器的视觉测试。

目录

  1. 简介
  2. 文本格式化
  3. 标题
  4. 列表
  5. 代码示例
  6. 引用块
  7. 表格
  8. 链接和图片
  9. 高级-mdx-特性
  10. 最佳实践

简介

MDX 是一种强大的格式,它将 Markdown 的简洁性与 JSX 的灵活性结合在一起。它允许你在 Markdown 内容中无缝导入和使用 React 组件,非常适合技术文档、博客文章和交互式内容。

什么是 MDX?

MDX 代表 Markdown + JSX。它是一种可编写的格式,允许你在 Markdown 文档中嵌入 JSX。这使你能够:

  • 使用 Markdown 轻松编写长篇内容
  • 在内容中导入和使用 React 组件
  • 创建交互式示例和演示
  • 构建可重用的内容块
  • 使用 TypeScript 保持类型安全

为什么使用 MDX?

使用 MDX 作为你的内容格式有几个令人信服的理由:

  1. 组件可重用性:编写一次组件,随处使用
  2. 交互性:创建引人入胜的交互式文档
  3. 类型安全:利用 TypeScript 获得更好的开发体验
  4. 灵活性:结合 Markdown 和 React 的优点
  5. 开发体验:使用熟悉的工具和语法

文本格式化

MDX 支持所有标准的 Markdown 文本格式化选项。让我们详细探讨每一种。

基本文本样式

以下是在 MDX 中设置文本样式的基本方法:

  • 粗体文本 使用双星号:**bold**
  • 斜体文本 使用单星号:*italic*
  • 粗斜体 使用三星号:***bold and italic***
  • ~~删除线~~ 使用双波浪号:~~strikethrough~~
  • 内联代码 使用反引号:`code`

组合样式

你还可以用有趣的方式组合这些样式:

  • 粗体包含 嵌套斜体 文本
  • 斜体包含 嵌套粗体 文本
  • 粗体内部包含 内联代码
  • 代码内部包含 **粗体**(虽然这可能不会按预期工作)

段落和换行

在 Markdown 中,段落由空行分隔。这是一个单独的段落,它在多行上继续而没有空行,它将被渲染为一个连续的段落。

要创建新段落,只需添加一个空行。

你也可以在行末使用两个空格 来创建换行而不开始新段落。


标题

MDX 支持六个级别的标题,从 H1 到 H6:

一级标题

二级标题

三级标题

四级标题

五级标题
六级标题

标题也可以使用下划线创建(适用于 H1 和 H2):

另一种 H1 样式

另一种 H2 样式

标题最佳实践

  • 每个文档只使用一个 H1(通常是标题)
  • 保持逻辑层次结构(不要跳过级别)
  • 保持标题简洁和描述性
  • 一致使用句首大写或标题大写

列表

列表对于组织信息至关重要。MDX 支持有序和无序列表,并具有无限嵌套。

无序列表

你可以使用 -*+ 创建无序列表:

  • 第一项
  • 第二项
  • 第三项
    • 嵌套项 1
    • 嵌套项 2
      • 深度嵌套项
      • 另一个深度嵌套项
    • 返回第二层
  • 第四项

有序列表

有序列表使用数字后跟句点:

  1. 第一步
  2. 第二步
  3. 第三步
    1. 子步骤 A
    2. 子步骤 B
    3. 子步骤 C
  4. 第四步

混合列表

你可以混合有序和无序列表:

  1. 第一个有序项
    • 无序子项
    • 另一个无序子项
  2. 第二个有序项
    1. 有序子项
    2. 另一个有序子项
      • 混合嵌套项
      • 另一个混合嵌套项

任务列表

一些 Markdown 处理器支持任务列表(GitHub 风格):

  • [x] 已完成任务
  • [x] 另一个已完成任务
  • [ ] 待完成任务
  • [ ] 另一个待完成任务
    • [x] 已完成子任务
    • [ ] 待完成子任务

定义列表

定义列表非常适合术语表:

术语 1 : 术语 1 的定义

术语 2 : 术语 2 的定义 : 术语 2 的替代定义


代码示例

代码块对于技术文档至关重要。MDX 提供了出色的语法高亮支持。

内联代码

使用单个反引号表示内联代码:const greeting = 'Hello, World!'

你也可以在行内引用 变量函数()文件名.ts

基本代码块

使用三个反引号创建代码块:

这是一个没有语法高亮的纯文本代码块
它保留格式和缩进

TypeScript 示例

// TypeScript 类型示例
interface User {
  id: number;
  name: string;
  email: string;
  role: 'admin' | 'user';
}

function getUserById(id: number): User | null {
  // 实现代码
  return null;
}

const user: User = {
  id: 1,
  name: 'John Doe',
  email: 'john@example.com',
  role: 'admin',
};

Python 示例

# Python 示例
from typing import List, Optional
from dataclasses import dataclass

@dataclass
class User:
    id: int
    name: str
    email: str
    is_active: bool = True

def get_active_users(users: List[User]) -> List[User]:
    """筛选并返回活跃用户"""
    return [user for user in users if user.is_active]

def find_user_by_email(users: List[User], email: str) -> Optional[User]:
    """通过邮箱地址查找用户"""
    for user in users:
        if user.email == email:
            return user
    return None

# 使用示例
users = [
    User(1, "Alice", "alice@example.com"),
    User(2, "Bob", "bob@example.com", False),
    User(3, "Charlie", "charlie@example.com"),
]

active_users = get_active_users(users)
user = find_user_by_email(users, "alice@example.com")

引用块

引用块非常适合突出显示重要信息、引用或标注。

基本引用块

这是一个简单的引用块。它非常适合突出显示重要信息或包含来自其他来源的引用。

嵌套引用块

这是外层引用块。

这是嵌套的引用块。

这是深度嵌套的引用块。

包含多个段落的引用块

这是引用块的第一段。

这是引用块的第二段。你可以通过使用带有 > 字符的空行在单个引用块中包含多个段落。

这是第三段。

包含其他元素的引用块

引用块中的标题

你可以在引用块中包含 格式化文本斜体 甚至 代码

  • 列表项 1
  • 列表项 2
  • 列表项 3
// 甚至代码块!
console.log('来自引用块的问候');

不同类型的标注

注意: 这是提供额外上下文的信息性注释。

警告: 这是突出显示潜在问题的警告消息。

提示: 这是提供有用建议的帮助提示。

重要: 这是不应忽视的关键信息。


表格

表格非常适合呈现结构化数据。MDX 支持 GitHub 风格的 Markdown 表格。

基本表格

| 姓名 | 年龄 | 职业 | |---------|-----|-------------| | Alice | 28 | 开发者 | | Bob | 32 | 设计师 | | Charlie | 25 | 产品经理 |

带对齐的表格

| 左对齐 | 居中对齐 | 右对齐 | |:-------------|:--------------:|--------------:| | 左边 | 居中 | 右边 | | 文本 | 文本 | 文本 | | 更多 | 数据 | 这里 |

复杂表格

| 功能 | 免费版 | 专业版 | 企业版 | |---------|:----:|:---:|:----------:| | 用户数 | 5 | 25 | 无限 | | 存储空间 | 10 GB | 100 GB | 无限 | | 支持 | 邮件 | 优先 | 24/7 电话 | | API 访问 | ❌ | ✅ | ✅ | | 自定义域名 | ❌ | ✅ | ✅ | | 分析 | 基础 | 高级 | 定制 | | 价格 | 0/0/月 | 29/月 | 联系我们 |

包含代码的表格

| 方法 | 端点 | 描述 | |--------|----------|-------------| | GET | /api/users | 获取所有用户 | | GET | /api/users/:id | 获取特定用户 | | POST | /api/users | 创建新用户 | | PUT | /api/users/:id | 更新用户 | | DELETE | /api/users/:id | 删除用户 |

对比表格

| 功能 | React | Vue | Angular | Svelte | |---------|-------|-----|---------|--------| | 学习曲线 | 中等 | 容易 | 陡峭 | 容易 | | 性能 | 优秀 | 优秀 | 良好 | 优秀 | | 打包大小 | 中等 | 小 | 大 | 极小 | | TypeScript | ✅ | ✅ | ✅ (内置) | ✅ | | 社区 | 庞大 | 大 | 大 | 增长中 | | 支持方 | Meta | 独立 | Google | 独立 |


链接和图片

基本链接

这是一个到 Google 的链接。

你也可以使用引用式链接,像这样

带标题的链接

这是一个带标题的链接:MDN Web Docs

自动链接

URL 和电子邮件地址可以自动转换为链接:

  • https://www.github.com
  • contact@example.com

内部链接

图片语法

Markdown 中的图片使用类似于链接的语法:

替代文本 带标题的替代文本

带链接的图片

你可以通过将图片包装在链接中使其可点击:

替代文本


高级 MDX 特性

MDX 超越了标准 Markdown,允许你在内容中直接使用 JSX 和 React 组件。

导入组件

在 MDX 中,你可以导入和使用 React 组件:

import { CustomComponent } from '@/components/CustomComponent'

<CustomComponent prop1="value1" prop2="value2" />

内联 JSX

你可以在 MDX 中直接编写 JSX:

<div className="custom-wrapper">
  <h3>自定义标题</h3>
  <p>这是 JSX 内容!</p>
</div>

使用 JavaScript 表达式

MDX 支持 JavaScript 表达式:

当前年份是 {new Date().getFullYear()}

随机数:{Math.floor(Math.random() * 100)}

组件属性

你可以向组件传递属性,包括函数:

<Button
  onClick={() => alert('已点击!')}
  variant="primary"
  size="large"
>
  点击我
</Button>

条件渲染

{true && <p>这将被渲染</p>}
{false && <p>这不会被渲染</p>}

{condition ? <ComponentA /> : <ComponentB />}

遍历数组

{['React', 'Vue', 'Angular', 'Svelte'].map((framework) => (
  <Badge key={framework}>{framework}</Badge>
))}

高级模式

自定义 MDX 组件

你可以用自定义组件替换默认的 Markdown 元素:

// mdx-components.tsx
import type { MDXComponents } from 'mdx/types'
import { Code } from '@/components/Code'
import { Heading } from '@/components/Heading'
import { Image } from '@/components/Image'

export function useMDXComponents(components: MDXComponents): MDXComponents {
  return {
    h1: (props) => <Heading level={1} {...props} />,
    h2: (props) => <Heading level={2} {...props} />,
    h3: (props) => <Heading level={3} {...props} />,
    code: (props) => <Code {...props} />,
    img: (props) => <Image {...props} />,
    ...components,
  }
}

语法高亮

对于高级语法高亮,你可以使用 Shiki 或 Prism 等库:

import { getHighlighter } from 'shiki'

export async function highlightCode(code: string, lang: string) {
  const highlighter = await getHighlighter({
    themes: ['github-dark', 'github-light'],
    langs: ['javascript', 'typescript', 'jsx', 'tsx', 'python', 'rust'],
  })

  return highlighter.codeToHtml(code, {
    lang,
    themes: {
      light: 'github-light',
      dark: 'github-dark',
    },
  })
}

Frontmatter 处理

处理 MDX 文件中的 frontmatter 元数据:

interface FrontMatter {
  title: string
  description: string
  date: string
  author: string
  tags: string[]
  published: boolean
}

export function processFrontMatter(frontmatter: FrontMatter) {
  return {
    ...frontmatter,
    date: new Date(frontmatter.date),
    tags: frontmatter.tags.map(tag => tag.toLowerCase()),
  }
}

动态内容加载

动态加载 MDX 内容:

import fs from 'fs/promises'
import path from 'path'
import matter from 'gray-matter'

export async function getMDXContent(slug: string) {
  const filePath = path.join(process.cwd(), 'content', `${slug}.mdx`)
  const source = await fs.readFile(filePath, 'utf-8')
  const { content, data } = matter(source)

  return {
    content,
    frontmatter: data,
  }
}

export async function getAllPosts() {
  const contentDir = path.join(process.cwd(), 'content')
  const files = await fs.readdir(contentDir)

  const posts = await Promise.all(
    files
      .filter(file => file.endsWith('.mdx'))
      .map(async file => {
        const slug = file.replace(/\.mdx$/, '')
        const content = await getMDXContent(slug)
        return { slug, ...content }
      })
  )

  return posts.sort((a, b) => {
    return new Date(b.frontmatter.date).getTime() - new Date(a.frontmatter.date).getTime()
  })
}

数学表达式

如果你的 MDX 设置支持数学公式(通过 remark-math 或 KaTeX),你可以包含数学表达式。以下是如何编写它们的示例:

内联数学

对于内联数学,你通常使用单美元符号或括号表示法:

内联数学:$E = mc^2$\(E = mc^2\)

块级数学

对于显示数学块,使用双美元符号或方括号表示法:

b±b24ac2a\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}

复杂表达式

ex2dx=π\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}

常见数学符号示例

分数

分子分母\frac{分子}{分母}

平方根

xxn\sqrt{x} 或 \sqrt[n]{x}

求和

i=1nxi\sum_{i=1}^{n} x_i

积分

abf(x)dx\int_{a}^{b} f(x) dx

希腊字母

α,β,γ,Δ,Ω\alpha, \beta, \gamma, \Delta, \Omega

矩阵

abcd\begin{matrix} a & b \\ c & d \end{matrix}

其他资源