近日接到一个小的需求,目标是实现一个AI问答的页面,该页面使用markdown语法输出内容,但是领导希望能够支持图表和流程图的内容输出。这里实现了echarts、chartjs、mermaid的语法支持。
1. 安装markdown-it
npm install markdown-it chart.js echarts mermaid
2. 使用
首先初始化markdown-it实例,并配置基本选项:
javascript
const md = new MarkdownIt({
html: true, // 启用HTML标签
breaks: true, // 转换换行符为<br>
linkify: true, // 自动转换URL为链接
typographer: true // 启用语言中性的替换
})
自定义fence渲染规则
通过扩展markdown-it的fence规则,我们可以支持自定义的代码块渲染: 在Markdown中,fence(围栏)代码块是指使用三个反引号 (```) 包裹的代码块
md.use(function (md) {// 重写fence渲染规则
md.renderer.rules.fence = function (tokens, idx, options, env, slf) {
// 渲染逻辑
}
- `tokens`: 包含所有解析后的标记的数组
- `idx`: 当前处理的标记索引
- `options`: markdown-it的配置选项
- `env`: 环境变量
- `slf`: 渲染器自身的引用
基本结构:
// 测试数据
const answer = ref(`
# Hello\n## Hi\n> hello world
\`\`\`mermaidChart
sequenceDiagram
participant Alice
participant Bob
Alice->>John: Hello John, how are you?
loop HealthCheck
John->>John: Fight against hypochondria
end
Note right of John: Rational thoughts <br/>prevail!
John-->>Alice: Great!
John->>Bob: How about you?
Bob-->>John: Jolly good!
`)
const eChartOption = ref(null) // 存储 ECharts 配置
md.use(function (md) {
md.renderer.rules.fence = function (tokens, idx, options, env, slf) {
console.log('tokens', tokens)
// 此处判断是否为 echarts 代码块
if (tokens[idx].info === "echarts") {
eChartOption.value = JSON.parse(tokens[idx].content) //此处表示将内容存起来,存到当前页面的变量去
return `<div id="echarts-id" style="width: 600px;height:400px;"></div>`
} else if (tokens[idx].info === "chartjs") {// 此处判断是否为 chartjs 代码块
eChartOption.value = JSON.parse(tokens[idx].content)
return `<canvas id="chartjs-id"></canvas>`
} else if (tokens[idx].info === "mermaidChart") {// 此处判断是否为 mermaidChart 代码块
const code = tokens[idx].content.trim()
eChartOption.value = code
return `<div id="mermaid-id" class="mermaid">${code}</div>`
} else { // 其他代码块
return `<pre><code class='languge-${tokens[idx].info}'>${tokens[idx].content}</code></pre>`;
}
}
})
3. 图表渲染实现
在组件挂载后,我们需要初始化各种图表:
// 在组件挂载时加载设置
onMounted(function () {
nextTick(() => {
// 渲染ECharts
if (document.getElementById('echarts-id')) {
const chartDom = document.getElementById('echarts-id')
const myChart = echarts.init(chartDom)
myChart.setOption(eChartOption.value)
}
// 渲染Chart.js
if (document.getElementById('chartjs-id')) {
const ctx = document.getElementById('chartjs-id');
console.log('chartjs-id', ctx)
new Chart(ctx, eChartOption.value);
}
// 渲染Mermaid
if (document.getElementById('mermaid-id')) {
mermaid.initialize({ startOnLoad: true });
// 通过 id 获取元素并渲染图表
const mermaidChart = document.getElementById('mermaid-id');
if (mermaidChart) {
mermaid.init(undefined, mermaidChart);
}
}
})
loadSettingsFromStorage()
})
<div class="answer-area">
<div v-if="renderedAnswer" class="markdown-body" v-html="renderedAnswer" />
<div v-else class="placeholder">
<template v-if="loading">
<div class="thinking">
<span>思考中</span>
<span class="thinking-spinner"></span>
</div>
</template>
<template v-else>
你好!很高兴见到你。有什么我可以帮忙的吗?
</template>
</div>
</div>
renderedAnswer.value = md.render(answer.value)// 渲染语句
4. 使用示例
4.1 ECharts示例
// echarts 测试数据
const answer = ref(`
# Hello\n## Hi\n> hello world
\`\`\`echarts
{
"title": {
"text": "第一个 ECharts 实例"
},
"tooltip": {},
"legend": {
"data":["小红", "小明", "小黑"]
},
"xAxis": {
"data": ["语文","数学","英语"]
},
"yAxis": {},
"series": [
{
"name": "小红",
"type": "bar",
"data": [45, 15, 32]
},
{
"name": "小明",
"type": "bar",
"data": [44, 14, 33]
},
{
"name": "小黑",
"type": "bar",
"data": [38, 10, 35]
}
]
}
`)
4.2 Chart.js示例
// chartjs 测试数据
const answer = ref(`
# Hello\n## Hi\n> hello world
\`\`\`chartjs
{
"type": "line",
"data": {
"labels": ["一月", "二月", "三月", "四月", "五月", "六月", "七月"],
"datasets": [
{
"label": "我的第一个数据集",
"data": [65, 59, 80, 81, 56, 55, 40],
"fill": false,
"borderColor": "rgb(75, 192, 192)",
"tension": 0.1
}
]
}
}
`)
4.3 Mermaid示例
// mermaid 测试数据
const answer = ref(`
# Hello\n## Hi\n> hello world
\`\`\`mermaidChart
sequenceDiagram
participant Alice
participant Bob
Alice->>John: Hello John, how are you?
loop HealthCheck
John->>John: Fight against hypochondria
end
Note right of John: Rational thoughts <br/>prevail!
John-->>Alice: Great!
John->>Bob: How about you?
Bob-->>John: Jolly good!
`)
单纯记录一下解决方案笔记,若有写的不好的地方烦请各位大佬指教一下~
参考这位大佬的文章:记一次为markdown-it添加echart支持