前言
Markdown 是一种广受欢迎的轻量级标记语言,便于书写和格式化内容。在实际开发中,我们常常需要在项目中动态渲染 Markdown 内容,同时满足高亮代码块、支持公式渲染或流程图绘制等扩展需求。本文将通过一个 Vue 示例,讲解如何结合 MarkdownIt
和相关插件实现 Markdown 内容的动态展示。
效果预览
我们将实现一个问答界面:
- 用户的提问和回答会动态渲染。
- Markdown 支持多种格式扩展,如任务列表、公式(KaTeX)、流程图(Mermaid)等。
技术实现
1. 项目依赖安装
我们需要安装以下依赖(根据自己的需求去安装插件):
npm install markdown-it highlight.js katex mermaid markdown-it-sub markdown-it-sup markdown-it-emoji markdown-it-task-lists markdown-it-footnote markdown-it-deflist markdown-it-abbr markdown-it-ins markdown-it-mark
2. MarkdownIt 配置
在 Vue 组件中,首先初始化 MarkdownIt
实例,并加载所需插件:
import MarkdownIt from 'markdown-it';
import hljs from 'highlight.js';
import mermaid from 'mermaid';
const katex = require('katex');
import MarkdownItMermaid from '@/utils/markdown-it-plugin-mermaid';
import 'katex/dist/katex.min.css';
import 'highlight.js/styles/default.css';
mermaid.initialize({ startOnLoad: true });
const mdi = new MarkdownIt({
html: true,
xhtmlOut: true,
breaks: true,
langPrefix: 'language-',
linkify: true,
typographer: true,
quotes: '“”‘’',
highlight: (str, lang) => {
if (lang && hljs.getLanguage(lang)) {
try {
return `<pre class="hljs"><code>${hljs.highlight(str, { language: lang, ignoreIllegals: true }).value}</code></pre>`;
} catch (__) {}
}
return `<pre class="hljs"><code>${mdi.utils.escapeHtml(str)}</code></pre>`;
},
})
.use(require('markdown-it-sub'))
.use(require('markdown-it-sup'))
.use(require('markdown-it-emoji'))
.use(require('markdown-it-task-lists'))
.use(require('markdown-it-footnote'))
.use(require('markdown-it-deflist'))
.use(require('markdown-it-abbr'))
.use(require('markdown-it-ins'))
.use(require('markdown-it-mark'))
.use(MarkdownItMermaid);
3.渲染html
...
<div v-html="initPage(item[0])"></div>
...
initPage(item){
return mdi.render(this.preprocessMarkdown(item));// 将文章内容片段组合并渲染
},
preprocessMarkdown(markdownText) {
const inlineMathRegex = /\$([^\$]+?)\$/g;
markdownText = markdownText.replace(inlineMathRegex, (match, tex) => {
try {
return katex.renderToString(tex, {
throwOnError: true,
displayMode: false,
globalGroup: true, // or use \global\let
macros:{
"\\RR": "\\mathbb{R}",
},
output:'html',
});
} catch (e) {
return `<span class="error">Error rendering math: ${e.message}</span>`;
}
});
// 使用正则表达式匹配块级LaTeX数学公式
const blockMathRegex = /\$\$([\s\S]*?)\$\$/g;
markdownText = markdownText.replace(blockMathRegex, (match, tex) => {
try {
return '<div class="math-block">' + katex.renderToString(tex, {
throwOnError: true,
displayMode: false,
}) + '</div>';
} catch (e) {
return `<div class="math-block error">Error rendering math: ${e.message}</div>`;
}
});
return markdownText;
},