markdownit + katex + highlight 构建gpt对话渲染

 封装渲染函数,对传入的content解析,最后v-html插入即可。 

import MarkdownIt from "markdown-it";
import texmath from "markdown-it-texmath";
import katex from "katex";
import hljs from "highlight.js";
import "katex/dist/katex.min.css";
// import "highlight.js/styles/github.css";
import "highlight.js/styles/atom-one-dark.css";
import DOMPurify from "dompurify";

// 初始化 markdown-it 实例(只初始化一次)
const md = new MarkdownIt({
    html: true,
    linkify: true,
    typographer: true,
    highlight: function (str, lang) {
        if (lang && hljs.getLanguage(lang)) {
            try {
                return hljs.highlight(str, { language: lang }).value;
            } catch (__) { }
        }
        return ""; // 使用默认的高亮
    },
}).use(texmath, {
    engine: katex,
    delimiters: "dollars",
    katexOptions: {
        macros: {
            "\\RR": "\\mathbb{R}",
            "\\abs": ["\\left|#1\\right|", 1],
        },
    },
});

/**
 * 渲染Markdown内容为HTML
 * @param content Markdown格式的字符串
 * @returns 渲染后的HTML字符串,可直接用于v-html
 */
export default function renderMarkdown(content) {
    //     content = `# 混合内容示例

    // ## 数学与代码结合

    // 计算圆的面积公式: $A = \\pi r^2$

    // 实现代码:

    // \`\`\`python
    // import math

    // def circle_area(radius):
    //     """计算圆的面积"""
    //     return math.pi * radius ** 2

    // # 示例使用
    // print(f"半径为5的圆面积: {circle_area(5):.2f}")
    // \`\`\`

    // ## 列表中的公式

    // 1. 勾股定理: $a^2 + b^2 = c^2$
    // 2. 二次方程求根公式:
    //    $$
    //    x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}
    //    $$
    // 3. 欧拉公式: $e^{i\\pi} + 1 = 0$

    // ## 表格示例

    // | 函数名 | 描述 | 公式 |
    // |--------|------|------|
    // | 正弦函数 | 三角函数 | $\\sin(x)$ |
    // | 指数函数 | 自然指数 | $e^x$ |
    // | 对数函数 | 自然对数 | $\\ln(x)$ |
    // `
    return DOMPurify.sanitize(md.render(content));
}

css部分,可以根据渲染出来的html结构自己配css,下面是我用到的css代码,可以直接复制然后进行微调。

.text {
  padding: 10px 20px;
  background-color: rgba(255, 255, 255, 0.7);
  border-radius: 10px;
  white-space: normal;
  word-break: break-all;
  border: 1px solid #e1e4e8;
  color: #24292e;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica,
  Arial, sans-serif;
  font-size: 16px;
}

/* 标题样式 */
.text :deep(h1) {
  font-size: 2em;
  border-bottom: 1px solid #eaecef;
  padding-bottom: 0.3em;
  margin-top: 24px;
  margin-bottom: 16px;
  font-weight: 600;
  line-height: 1.25;
}

.text :deep(h2) {
  font-size: 1.5em;
  border-bottom: 1px solid #eaecef;
  padding-bottom: 0.3em;
  margin-top: 24px;
  margin-bottom: 16px;
  font-weight: 600;
  line-height: 1.25;
}

.text :deep(h3) {
  font-size: 1.25em;
  margin-top: 24px;
  margin-bottom: 16px;
  font-weight: 600;
  line-height: 1.25;
}

.text :deep(h4) {
  font-size: 1em;
  margin-top: 24px;
  margin-bottom: 16px;
  font-weight: 600;
  line-height: 1.25;
}

.text :deep(h5) {
  font-size: 0.875em;
  margin-top: 24px;
  margin-bottom: 16px;
  font-weight: 600;
  line-height: 1.25;
}

.text :deep(h6) {
  font-size: 0.85em;
  margin-top: 24px;
  margin-bottom: 16px;
  font-weight: 600;
  line-height: 1.25;
  color: #6a737d;
}

/* 段落和文字样式 */
.text :deep(p) {
  margin-top: 0;
  margin-bottom: 16px;
}

.text :deep(strong) {
  font-weight: 600;
}

.text :deep(em) {
  font-style: italic;
}

.text :deep(del) {
  text-decoration: line-through;
}

/* 代码样式 */
.text :deep(code) {
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  background-color: rgba(27, 31, 35, 0.05);
  padding: 0.2em 0.4em;
  border-radius: 3px;
  font-size: 85%;
}

.text :deep(pre) {
  background-color: #f6f8fa;
  padding: 16px;
  border-radius: 6px;
  overflow: auto;
  line-height: 1.45;
  margin-bottom: 16px;
}

.text :deep(pre code) {
  background-color: transparent;
  padding: 0;
  border-radius: 0;
  font-size: 100%;
}

/* 引用块 */
.text :deep(blockquote) {
  border-left: 4px solid #dfe2e5;
  color: #6a737d;
  padding: 0 1em;
  margin: 0 0 16px 0;
}

.text :deep(blockquote > :first-child) {
  margin-top: 0;
}

.text :deep(blockquote > :last-child) {
  margin-bottom: 0;
}

/* 列表样式 */
.text :deep(ul),
.text :deep(ol) {
  padding-left: 2em;
  margin-top: 0;
  margin-bottom: 16px;
}

.text :deep(li) {
  margin-bottom: 0.25em;
}

.text :deep(li > p) {
  margin-bottom: 0.25em;
}

.text :deep(li + li) {
  margin-top: 0.25em;
}

.text :deep(ul ul),
.text :deep(ul ol),
.text :deep(ol ol),
.text :deep(ol ul) {
  margin-top: 0;
  margin-bottom: 0;
}

/* 表格样式 */
.text :deep(table) {
  border-collapse: collapse;
  width: 100%;
  margin: 16px 0;
  display: block;
  overflow: auto;
}

.text :deep(table th) {
  font-weight: 600;
  background-color: #f6f8fa;
}

.text :deep(table th),
.text :deep(table td) {
  border: 1px solid #dfe2e5;
  padding: 6px 13px;
}

.text :deep(table tr) {
  background-color: #fff;
  border-top: 1px solid #c6cbd1;
}

.text :deep(table tr:nth-child(2n)) {
  background-color: #f6f8fa;
}

/* 链接样式 */
.text :deep(a) {
  color: #0366d6;
  text-decoration: none;
}

.text :deep(a:hover) {
  text-decoration: underline;
}

/* 分割线 */
.text :deep(hr) {
  height: 0.25em;
  padding: 0;
  margin: 24px 0;
  background-color: #e1e4e8;
  border: 0;
}

/* 图片样式 */
.text :deep(img) {
  max-width: 100%;
  box-sizing: content-box;
  background-color: #fff;
  border-radius: 4px;
}

.text :deep(img[align="right"]) {
  padding-left: 20px;
}

.text :deep(img[align="left"]) {
  padding-right: 20px;
}

/* 任务列表 */
.text :deep(.task-list-item) {
  list-style-type: none;
}

.text :deep(.task-list-item-checkbox) {
  margin: 0 0.2em 0.25em -1.6em;
  vertical-align: middle;
}

/* Katex 公式样式 */
.text :deep(.katex) {
  font-size: 1.1em;
}

/* 行内公式 */
.text :deep(.katex-display) {
  margin: 1em 0;
  overflow-x: auto;
  overflow-y: hidden;
}

/* 代码块标题 */
.text :deep(.code-block-title) {
  background: #f6f8fa;
  border: 1px solid #e1e4e8;
  border-bottom: 0;
  padding: 6px 12px;
  font-size: 85%;
  font-weight: 600;
  border-radius: 6px 6px 0 0;
  margin-bottom: -16px;
}

/* 脚注 */
.text :deep(.footnotes) {
  font-size: 85%;
  color: #6a737d;
  border-top: 1px solid #e1e4e8;
  margin-top: 24px;
}

.text :deep(.footnotes li) {
  margin-bottom: 0.5em;
}

.text :deep(.footnote-backref) {
  margin-left: 0.5em;
  text-decoration: none;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值