如何处理流式markdown语法数据,并不涉及数据公式,但是有代码块格式,渲染在页面上,
时间: 2025-06-21 11:22:38 浏览: 25
<think>好的,我现在需要解决用户的问题:如何在网页上解析和渲染带有代码块的流式Markdown数据,同时不处理数学公式。用户提到了使用Vue3、fetch请求以及相关库如@microsoft/fetch-event-source和markdown-it,还有highlight.js。首先,我需要理清整个流程,确保每一步都正确。
首先,流式数据的接收。用户已经提到使用@microsoft/fetch-event-source,这个库可以帮助处理服务器发送的事件(SSE),允许逐步接收数据。这比普通的fetch更合适,因为可以实时处理数据块。需要配置fetchEventSource,设置正确的请求头和onmessage回调,将接收到的数据块追加到已有的内容中。
接下来是Markdown的解析。用户选择markdown-it这个库,它支持插件,可以灵活配置。不过用户要求不处理数学公式,所以需要禁用相关的语法,比如避免识别$...$或$$...$$。可能需要配置markdown-it的选项,或者使用插件来忽略这些部分。例如,markdown-it通常默认会处理一些内联HTML或特殊符号,但数学公式可能需要特定的插件,所以不引入这些插件应该就能避免解析数学内容。
然后是代码块的高亮显示。highlight.js可以自动检测代码块的语言并进行高亮。在Vue组件中,每当Markdown内容更新后,需要调用highlight.highlightAll()来应用高亮。但要注意,频繁调用可能会影响性能,所以最好在内容更新完成后执行一次,比如使用nextTick或在追加数据后调用。
在Vue3中,响应式数据的使用是关键。需要将接收到的Markdown内容存储在响应式变量中,比如使用ref,这样当内容更新时,视图会自动重新渲染。不过,直接更新大段文本可能会导致性能问题,所以分块追加数据更有效率,每次接收到数据块就追加到现有的内容中。
关于安全性,用户输入的Markdown可能包含恶意脚本,所以使用DOMPurify来净化生成的HTML是必要的。这可以防止XSS攻击,确保只保留安全的标签和属性。在markdown-it渲染后,将输出的HTML传递给DOMPurify进行处理,然后再插入到页面中。
接下来是代码结构。组件部分需要使用onMounted来启动数据流的获取,在setup函数中初始化内容和相关的配置。使用markdown-it的render方法将Markdown转换为HTML,注意要禁用html选项以避免原生HTML被解析,这样可以减少安全隐患,同时依靠DOMPurify进一步清理。
可能遇到的挑战包括流式数据的拼接处理,确保每次接收的数据块正确追加,以及高亮显示的及时应用。另外,需要注意markdown-it的配置是否正确,比如是否意外启用了一些不想要的语法扩展,导致数学公式被错误处理。同时,测试不同代码块语言的高亮是否正常工作,可能需要引入特定的语言包或配置highlight.js的自动检测。
最后,示例代码需要展示完整的流程,从安装依赖、引入库、组件配置到数据接收和渲染。确保代码中的关键部分有注释,帮助用户理解每一步的作用。比如,在onmessage回调中处理数据块,使用v-html指令来渲染净化后的HTML内容,以及如何在更新后触发高亮显示。
总结步骤:
1. 使用fetch-event-source处理流式数据接收。
2. 配置markdown-it,禁用不需要的功能(如数学公式),启用代码块解析。
3. 使用DOMPurify对生成的HTML进行清理,防止XSS。
4. 在Vue组件中响应式更新内容,分块追加数据。
5. 每次内容更新后,调用highlight.js进行代码高亮。
6. 处理组件销毁时取消数据请求,避免内存泄漏。
需要验证各个步骤是否协同工作,例如流式数据是否实时显示,代码块是否高亮,数学公式是否被忽略,以及净化是否有效。测试不同的Markdown输入案例,确保符合用户需求。</think>以下是解析和渲染流式Markdown数据(含代码块)的完整解决方案:
### 一、实现步骤
1. **流式数据接收**
使用`fetchEventSource`建立长连接,通过事件流实时接收数据片段:
```javascript
import { fetchEventSource } from '@microsoft/fetch-event-source';
const appendChunk = (chunk) => {
content.value += chunk;
// 触发高亮需在DOM更新后执行
nextTick(() => {
hljs.highlightAll();
});
};
```
2. **Markdown解析配置**
创建禁用数学公式的解析器实例:
```javascript
const md = new MarkdownIt({
html: false, // 禁止原生HTML解析
linkify: true,
highlight: (str, lang) => { // 代码块处理钩子
return `<pre><code class="hljs ${lang}">${md.utils.escapeHtml(str)}</code></pre>`;
}
}).disable(['image']); // 按需禁用特定语法
```
3. **安全净化处理**
使用DOMPurify过滤危险内容:
```javascript
import DOMPurify from 'dompurify';
const safeHtml = computed(() => {
return DOMPurify.sanitize(md.render(content.value));
});
```
### 二、完整组件示例
```vue
<template>
<div class="markdown-container" v-html="safeHtml"></div>
</template>
<script setup>
import { ref, nextTick, onMounted, computed } from 'vue';
import MarkdownIt from 'markdown-it';
import hljs from 'highlight.js';
import 'highlight.js/styles/github.css';
import DOMPurify from 'dompurify';
import { fetchEventSource } from '@microsoft/fetch-event-source';
const content = ref('');
const md = new MarkdownIt({
html: false,
linkify: true,
highlight: (str, lang) => {
return `<pre><code class="hljs ${lang}">${md.utils.escapeHtml(str)}</code></pre>`;
}
});
const safeHtml = computed(() => {
return DOMPurify.sanitize(md.render(content.value));
});
onMounted(async () => {
await fetchEventSource('/api/stream', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt: "..." }),
onopen(response) {
if (response.ok) return;
throw new Error('Connection failed');
},
onmessage(ev) {
if (ev.data === '[DONE]') return;
appendChunk(ev.data);
},
onclose() {
console.log('Stream closed');
}
});
});
const appendChunk = (chunk) => {
content.value += chunk;
nextTick(() => {
document.querySelectorAll('pre code').forEach((block) => {
hljs.highlightElement(block);
});
});
};
</script>
```
### 三、关键优化点
1. **增量渲染**
通过`content.value += chunk`实现分段拼接,避免全量重渲染带来的性能损耗
2. **语法控制**
通过`md.disable()`方法关闭数学公式支持,确保`$...$`等符号作为普通文本显示
3. **样式适配**
推荐使用`github.css`主题样式表,与主流代码平台的显示风格保持一致
阅读全文
相关推荐


















