目 录CONTENT

文章目录

在Ant Design 页面添加Markdown文档前端展示

过客
2026-01-26 / 0 评论 / 1 点赞 / 3 阅读 / 0 字

身为程序员习惯用md来写文档,但在一些网站或中间件页面中,添加一些接口说明或文档,可以写Markdown文档再渲染成html到页面。浏览器不能直接渲染 .md 文件,需要借助 Markdown 解析库,这里用 marked + DOMPurify + highlight 来实现。

1. 安装依赖

yarn add marked dompurify highlight.js
  • marked:将Markdown 转 HTML;
  • DOMPurify:防止 XSS 攻击;
  • highlight:代码高亮。

2. 创建 Markdown 渲染组件

import React, { useEffect, useState } from 'react';
import './MarkdownRenderer.css'
import 'highlight.js/styles/atom-one-dark.min.css';
import { marked } from 'marked';
import DOMPurify from 'dompurify';
import hljs from 'highlight.js/lib/core';

// 导入需要的语言
import json from 'highlight.js/lib/languages/json';
import js from 'highlight.js/lib/languages/JavaScript';


interface MarkdownRendererProps {
    content: string; // Markdown 字符串
}

const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ content }) => {
    const [html, setHtml] = useState("");

    // 注册需要的语言
    hljs.registerLanguage('json', json);
    hljs.registerLanguage('js', js);
    // ...

    // 创建自定义渲染器
    const renderer = new marked.Renderer();

    renderer.code = ({ text, lang }: { text: string; lang?: string }) => {
        // 如果有指定语言且 highlight.js 支持
        if (lang && hljs.getLanguage(lang)) {
            const highlighted = hljs.highlight(text, { language: lang }).value;
            return `<pre><code class="hljs language-${lang}"> ${highlighted}</code></pre>`;
        }
        // 转义普通代码(防止 XSS)
        const escapedText = DOMPurify.sanitize(text, { ALLOWED_TAGS: [] });
        return `<pre><code> ${escapedText}</code></pre>`;
    };
    
    // 配置 marked
    marked.setOptions({
        renderer: renderer,
        gfm: true,
        breaks: true,
        pedantic: false,
    });
    

    useEffect(() => {
        const html = marked(content);
        const safeHtml = DOMPurify.sanitize(html.toString()); // 全局清洗防 XSS
        setHtml(safeHtml);
    }, [content]);

    return <div
        className="markdown-body"
        dangerouslySetInnerHTML={{ __html: html }}
    />
};

export default MarkdownRenderer;

3. 编辑CSS样式

这个可以根据自己需求调整,也可以网上找 markd 的样式下载

/* src/styles/markdown.css */
.markdown-body {
  font-size: 14px;
  line-height: 1.1;
  color: rgba(0, 0, 0, 0.85);
  word-wrap: break-word;
}

/* 标题 */
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
  margin-top: 24px;
  margin-bottom: 16px;
  font-weight: 600;
  line-height: 1;
}
.markdown-body h1 {
  font-size: 24px;
  border-bottom: 1px solid #e8e8e8;
  padding-bottom: 8px;
}
.markdown-body h2 {
  font-size: 20px;
  border-bottom: 1px solid #e8e8e8;
  padding-bottom: 8px;
}
.markdown-body h3 {
  font-size: 16px;
}
.markdown-body h4 {
  font-size: 14px;
}
.markdown-body h5,
.markdown-body h6 {
  font-size: 12px;
}

/* 段落 & 水平线 */
.markdown-body p,
.markdown-body blockquote,
.markdown-body ul,
.markdown-body ol,
.markdown-body dl,
.markdown-body table,
.markdown-body pre {
  margin-top: 0;
  margin-bottom: 16px;
}
.markdown-body hr {
  height: 1px;
  padding: 0;
  margin: 24px 0;
  background-color: #e8e8e8;
  border: 0;
}

/* 列表 */
.markdown-body ul,
.markdown-body ol {
  padding-left: 2em;
}
.markdown-body ul ul,
.markdown-body ul ol,
.markdown-body ol ol,
.markdown-body ol ul {
  margin-top: 0;
  margin-bottom: 0;
}
.markdown-body li > p {
  margin-top: 16px;
}

/* 引用 */
.markdown-body blockquote {
  padding: 0 1em;
  color: #666;
  border-left: 4px solid #d9d9d9;
}
.markdown-body blockquote > :first-child {
  margin-top: 0;
}
.markdown-body blockquote > :last-child {
  margin-bottom: 0;
}

/* 行内元素 */
.markdown-body code,
.markdown-body kbd,
.markdown-body pre,
.markdown-body samp {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
  font-size: 12px;
}
.markdown-body code {
  padding: 0.2em 0.4em;
  margin: 0;
  background-color: rgba(150, 150, 150, 0.1);
  border-radius: 6px;
}
.markdown-body pre {
  padding: 16px;
  overflow: auto;
  background-color: #f5f5f5;
  border-radius: 6px;
}
.markdown-body pre code {
  padding: 0;
  margin: 0;
  font-size: 100%;
  background-color: transparent;
  border-radius: 0;
}

/* 链接 */
.markdown-body a {
  color: #1890ff;
  text-decoration: none;
}
.markdown-body a:hover {
  text-decoration: underline;
}

/* 图片 */
.markdown-body img {
  max-width: 100%;
  height: auto;
  background-color: #fff;
  border: 1px solid #d9d9d9;
  border-radius: 6px;
  margin: 8px 0;
}

/* 表格 */
.markdown-body table {
  display: block;
  width: 100%;
  overflow: auto;
  margin: 16px 0;
  border-collapse: collapse;
  border-spacing: 0;
}
.markdown-body table th,
.markdown-body table td {
  padding: 8px 12px;
  border: 1px solid #d9d9d9;
  text-align: left;
}
.markdown-body table tr {
  background-color: #fff;
  border-top: 1px solid #d9d9d9;
}
.markdown-body table tr:nth-child(2n) {
  background-color: #fafafa;
}
.markdown-body table th {
  font-weight: 600;
  background-color: #fafafa;
}

/* 任务列表(可选) */
.markdown-body .task-list-item {
  list-style: none;
}
.markdown-body .task-list-item input[type='checkbox'] {
  margin-right: 4px;
}

4. 在Ant Design 页面中使用

假设 在项目下有md文件 /docs/help.md,在Ant Design 页面添加一个页面

import { Spin } from 'antd';
import MarkdownRenderer from '../../components/MarkdownRenderer';
import { useEffect, useState } from 'react';

const DocsPage = () => {
    const [mdContent, setMdContent] = useState('');
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        fetch('/docs/help.md')
            .then(res => res.text())
            .then(text => {
                setMdContent(text);
                setLoading(false);
            });
    }, []);

    if (loading) return <Spin tip="加载文档中..." />;

    return (
        <MarkdownRenderer content={mdContent} />
    );
};

export default DocsPage;

5. 测试效果

1
js
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区