components/mdx/index.tsx:标签映射§
把原生标签换成站点组件:
| Markdown / MDX | 组件行为 |
|---|---|
h2/h3/h4 | 保留 id,右侧加 § 锚点链接 |
a | 外链自动 target="_blank" + rel="noopener noreferrer" |
pre | 整块换成 CodeBlock(客户端) |
code | 有 language-* 类名时原样输出(给代码块用);否则做成行内代码样式 |
table | 外包一层横向滚动容器 |
Callout | MDX 里可直接写的提示框(tip / note / warn) |
这里有一个容易忽略的细节:pre 映射成客户端组件后,高亮后的 <code> 子节点仍作为 children 传入;CodeBlock 用 childrenArr[activeIdx] 显示当前 Tab 的高亮结果,同时用 data-files 里的原文做复制和预览。
components/mdx/code-block.tsx:交互最重的一块§
文件约 460 行,职责可以拆成四段。
1. 解析 props§
从 data-files JSON 解析文件列表;data-preview === "true" 时尝试构建预览文档。
2. buildPreviewDoc§
- 过滤出可预览语言
- 找 html(Prism 里叫
markup)、拼接所有 css 为<style>、所有 js 为<script> - 若有完整 html,则注入到
</head>/</body>前;否则生成一份默认深色底的壳页面 - 对
</style>/</script>做字符串拆开拼接,降低源码里误闭合标签的风险
3. UI:预览区 + Tab + 行号 + 复制§
- 预览:
iframe+sandbox="allow-scripts allow-forms allow-modals allow-popups"(故意没有allow-same-origin,降低沙箱逃逸面) - 重跑:
setFrameKey(k => k + 1)强制重挂 iframe - Tab:方向键 / Home / End;复制只复制当前文件原文
- 行号:按当前文件源码行数生成左侧 gutter
4. 文件类型图标§
根据扩展名渲染小徽章或 React 风格 SVG,纯展示,不影响逻辑。
可运行示例(三件套会合成独立文档):
<button id="go">点亮</button>data-files / 合并 / 高亮如何在服务端写进 AST,见本册「rehype 源码」章。更细的作者语法说明,见散篇里关于 MDX 代码块的专题文。下一章讲阅读进度子系统。