Skip to content

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

render-markdown

一个基于 React 的 Markdown 渲染组件,支持 GFM(GitHub Flavored Markdown)Tabs 标签、代码高亮、Mermaid 图表等功能。

渲染效果 整体渲染效果

技术方案

技术栈

类别 技术选型 说明
框架 React 18 组件库基础框架
构建工具 Vite 基于 Rollup 的极速构建器
语言 TypeScript 提供类型定义
样式方案 CSS Modules / 内联样式 轻量无外部依赖
代码规范 ESLint + Prettier 统一代码风格
发布工具 changesets 语义化版本管理与 changelog 生成

核心功能

  • GFM 支持: 完整的 GitHub Flavored Markdown 渲染
  • 增量渲染: 基于 morphdom 的 DOM 差异化更新,适用于流式输出场景
  • 代码高亮: 基于 highlight.js 的代码语法高亮
  • Mermaid 图表: 支持 Mermaid 语法渲染流程图、时序图等
  • Tab 标签页: 支持 Tab 标签页语法
  • Alert 提示框: 支持警告、提示等信息框
  • 目录锚点: 自动生成文档目录和锚点链接(自行实现目录渲染)
  • 代码复制: 一键复制代码块
  • 代码折叠: 支持代码块折叠展开
  • 深色模式: 自动适配深色/浅色主题

API

安装

npm install remons-render-markdown

导出内容

import RenderMarkdown, { markdownFormat, languagesCommon,  initHighlighter, useIncrementalRender } from 'remons-render-markdown';

默认导出

  • RenderMarkdown: React 组件,用于渲染 Markdown 内容

命名导出

  • markdownFormat: Markdown 解析函数,返回 { anchor: AnchorItem[], info: string }
  • languagesCommon: 默认支持的语言包配置(javascript, typescript, css, json, bash, xml, plaintext)
  • initHighlighter: 初始化高亮语言包的函数
  • useIncrementalRender: 增量渲染 hook,使用 morphdom 进行 DOM 差异化更新,适用于流式输出场景
  • renderMermaid: 独立的 Mermaid 图表渲染组件

RenderMarkdown 组件 Props

参数 类型 必填 默认值 说明
content string ✅ - Markdown 内容
createTime string ❌ - 创建时间,用于显示文档更新时间
isSlotMermaid boolean ❌ true 是否使用 Mermaid 插件渲染图表
isShowCollapsed boolean ❌ true 是否显示代码折叠按钮
codeType string ❌ - 指定代码类型(如 'javascript' 等),不传则按 Markdown 渲染
editButton React.ReactNode ❌ - 自定义编辑按钮
backTopTarget HTMLElement ❌ body 返回顶部按钮监听的容器
showDriverGuide boolean ❌ false 是否显示新手引导
showToc boolean ❌ false 是否显示目录(TOC)按钮和侧边栏

markdownFormat 函数

解析 Markdown 内容并返回结构化数据。

参数:

  • content: string - Markdown 文本内容

返回值:

{
  anchor: Array<{
    title: string;        // 标题文本
    href: string;         // 锚点链接
    nodeName: string;     // 节点名称,如 "H1", "H2"
    nodeTitle: string;    // 完整节点 HTML
    children: Array<...>; // 子标题
  }>;
  info: string;           // 渲染后的 HTML 字符串
}

initHighlighter 函数

注册自定义的代码高亮语言。

参数:

  • languages: Record<string, any> - 语言包对象,格式为 { languageName: languageModule }

示例:

import javascript from 'highlight.js/lib/languages/javascript';
import python from 'highlight.js/lib/languages/python';

initHighlighter({
  javascript,
  python,
});

使用方式

基础用法

import RenderMarkdown from 'remons-render-markdown';
import 'render-markdown/dist/index.css';

function App() {
  const markdownContent = `
# Hello World

This is a **Markdown** renderer.

\`\`\`javascript
console.log('Hello');
\`\`\`
  `;

  return <RenderMarkdown content={markdownContent} />;
}

完整示例

import RenderMarkdown from 'remons-render-markdown';
import 'render-markdown/dist/index.css';

function ArticlePage() {
  const content = `
# 文章标题

这是一篇示例文章。

## 代码示例

\`\`\`javascript
const greeting = 'Hello World';
console.log(greeting);
\`\`\`

## Mermaid 图表

\`\`\`mermaid
graph TD
  A[开始] --> B[处理]
  B --> C[结束]
\`\`\`
  `;

  return (
    <RenderMarkdown
      content={content}
      createTime="2026-07-23T12:00:00Z"
      isSlotMermaid={true}
      isShowCollapsed={true}
      editButton={<button>编辑</button>}
    />
  );
}

使用 markdownFormat 获取目录结构

import { markdownFormat } from 'remons-render-markdown';

async function TableOfContents() {
  const content = '# 标题1\n## 标题1.1\n## 标题1.2\n# 标题2';
  const { anchor, info } = await markdownFormat(content);
  
  console.log(anchor); 
  // [
  //   { title: '标题1', href: '标题1', nodeName: 'H1', children: [...] },
  //   { title: '标题2', href: '标题2', nodeName: 'H1', children: [] }
  // ]
  
  return <div dangerouslySetInnerHTML={{ __html: info }} />;
}

自定义代码高亮语言

import RenderMarkdown, { initHighlighter, languagesCommon } from 'remons-render-markdown';
import 'render-markdown/dist/index.css';
import python from 'highlight.js/lib/languages/python';
import go from 'highlight.js/lib/languages/go';

// 注册额外的语言
initHighlighter({
  ...languagesCommon,  // 包含默认语言
  python,
  go,
});

function App() {
  return (
    <RenderMarkdown
      content={`
\`\`\`python
def hello():
    print('Hello')
\`\`\`

\`\`\`go
package main
import "fmt"
func main() {
    fmt.Println("Hello")
}
\`\`\`
      `}
    />
  );
}

仅渲染特定代码类型

import RenderMarkdown from 'remons-render-markdown';
import 'render-markdown/dist/index.css';

function CodeViewer() {
  const code = `
const x = 1;
const y = 2;
console.log(x + y);
  `;

  return (
    <RenderMarkdown
      content={code}
      codeType="javascript"
      isSlotMermaid={false}
    />
  );
}

使用 useIncrementalRender 实现增量渲染

useIncrementalRender 适用于流式输出场景(如 AI 对话),通过 morphdom 实现高效的 DOM 差异化更新。

import { useIncrementalRender } from 'remons-render-markdown';

function StreamingContent({ content }) {
  const { anchors, hasContent, setInnerRef } = useIncrementalRender({
    content,
    // 可选:节流时间,默认 16ms
    throttleMs: 16,
  });

  return (
    <div>
      {hasContent && <div ref={setInnerRef} />}
      {anchors.length > 0 && (
        <ul>
          {anchors.map((item) => (
            <li key={item.href}>
              <a href={`#${item.href}`}>{item.title}</a>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

参数:

参数 类型 必填 默认值 说明
content string ✅ - Markdown 内容
codeType string ❌ - 代码类型,不传则按 Markdown 渲染
customRenderers MarkdownPlugin[] ❌ - 自定义 markdown-it 插件
throttleMs number ❌ 16 节流时间(ms)
onNodeDiscarded (el: HTMLElement) => void ❌ - 节点被 diff 移除后触发(含被移除子树的子节点),用于清理 React Root 等挂载状态

返回值:

属性 类型 说明
anchors AnchorItem[] 文档锚点列表
hasContent boolean 是否有内容
setInnerRef (node: HTMLDivElement) => void 内容容器的 ref 回调

增量渲染与自定义插件(customRenderers)的配合约定:

  1. 插件产出的容器节点(如 :::badge / :::linkCard / <plugin-container>)按"标签 + className"语义匹配,内容位移时不同类型的块不会被错配到旧节点上。
  2. 元素上 JS 后加的 data-* 属性(如初始化守卫位 data-xxx-inited)在 diff 后会被保留,"只初始化一次"的守卫逻辑不会在增量渲染中被重复触发。
  3. JS 动态插入的额外子节点(如 React 挂载点、收起按钮)默认会被 diff 移除;若需跨增量渲染保留,请给节点设置 data-md-persist 属性(见导出常量 MD_PERSIST_ATTR)。
  4. 被 diff 移除的节点会触发 onNodeDiscarded,请在此卸载挂载在其上的 React Root,避免内存泄漏。

关于语法

mermaid 图表

---
title: 图表标题
---
......... 图表内容
  • 折叠图 mermaid 渲染图

  • 缩略图 mermaid 渲染图

Tabs 标签页

依赖于 @mdit/plugin-tab 插件,参考 mdit-plugin-tab 的文档。 暂不支持 tabs 嵌套

语法示例:

:::markdown-tabs

@tab:active tab1
    ```javascript
        console.log('Hello');
    ```

@tab tab2 
    ```typescript
        console.log('World');
    ```
:::

tabs 渲染图

Alert 提示框

语法示例:

> [!warning]
> 我是一个警告信息

alert 渲染图

renderMermaid 方法

支持渲染独立的 Mermaid 图表渲染组件,支持缩放、全屏、下载、源码查看等功能。

import { renderMermaid } from 'remons-render-markdown';
import 'remons-render-markdown/dist/index.css';

function MermaidComponent() {
  const mermaidCode = `
---
title: 流程图示例
---
graph TD
  A[开始] --> B[处理]
  B --> C[结束]
  `;

  return (
    <div>
      {
        renderMermaid({ source: mermaidCode })
      }
    </div>
  );
}
参数 类型 必填 默认值 说明
source string ✅ - Mermaid 代码字符串,支持设置标题
debounceMs number ❌ 300 图表渲染时的 debounce 时间(毫秒)
enablePanzoom boolean ❌ true 是否启用缩放和平移功能
showDownload boolean ❌ true 是否显示下载按钮(支持 SVG/PNG 格式)
showSourceView boolean ❌ false 是否显示源码查看按钮和工具栏
showCollapse boolean ❌ false 是否显示折叠/展开按钮
defaultCollapsed boolean ❌ true 默认折叠状态
className string ❌ "" 自定义样式类名
minHeight number ❌ 200 最小高度(像素)

功能特性:

  • 缩放:支持放大、缩小、重置视图
  • 全屏:支持浏览器原生全屏模式
  • 下载:支持下载 SVG 和 PNG 格式
  • 源码查看:点击按钮可查看 Mermaid 源码
  • 折叠/展开:支持图表的折叠和展开
  • 缩略图模式:最小化时显示缩略图
  • 深色模式:自动适配主题

注意事项

  1. 样式引入:务必引入 remons-render-markdown/dist/index.css 以确保正确的样式渲染
  2. Mermaid 支持:当 isSlotMermaid 为 true 时,会自动渲染 mermaid 代码块为图表
  3. 代码高亮:请使用 initHighlighter 注册(必须)
  4. 安全性:外部链接会自动添加 target="_blank" 和 rel="noopener" 属性
  5. 性能优化:Mermaid 渲染会延迟执行,以优化首屏加载速度

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages