这个问题本质上是:第三方 LLM API(豆包 / 元宝 / Dify)返回的 Markdown / 结构化文本,如何在 Vue 中正确解析并尽量保留原始样式

下面我用「通用思路 + Vue3 实战代码」一步步说明。


一、先搞清楚:它们返回的是什么?

平台

常见返回格式

豆包

Markdown / 伪 HTML

元宝

Markdown

Dify

Markdown / JSON(含 answer字段)

👉 共同点

✅ 本质是 Markdown

✅ 需要 渲染为 HTML 并保留样式


二、整体方案(推荐)

Markdown → HTML → Vue v-html → 自定义样式

API 返回 Markdown
        ↓
markdown-it 解析
        ↓
HTML 字符串
        ↓
v-html 渲染
        ↓
CSS 还原“原有样式”

三、Vue3 标准解析方案(通用)

1️⃣ 安装依赖

npm install markdown-it markdown-it-highlightjs
npm install highlight.js

2️⃣ 封装统一 MarkdownRenderer 组件

<!-- components/MarkdownRenderer.vue -->
<template>
  <div class="markdown-wrapper" v-html="renderedHtml"></div>
</template>

<script setup>
import { ref, watchEffect } from 'vue'
import MarkdownIt from 'markdown-it'
import hljs from 'highlight.js'
import 'highlight.js/styles/github.css'

const props = defineProps({
  content: String
})

const md = new MarkdownIt({
  html: true,
  linkify: true,
  typographer: true,
  highlight(code, lang) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        return hljs.highlight(code, { language: lang }).value
      } catch {}
    }
    return ''
  }
})

const renderedHtml = ref('')

watchEffect(() => {
  renderedHtml.value = md.render(props.content || '')
})
</script>

<style scoped>
.markdown-wrapper {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto;
  line-height: 1.75;
  color: #333;
}

.markdown-wrapper h1,
.markdown-wrapper h2,
.markdown-wrapper h3 {
  margin-top: 24px;
  font-weight: 600;
}

.markdown-wrapper pre {
  background: #f6f8fa;
  padding: 16px;
  border-radius: 8px;
  overflow: auto;
}

.markdown-wrapper code {
  font-family: Menlo, Monaco, monospace;
}

.markdown-wrapper table {
  border-collapse: collapse;
  width: 100%;
}

.markdown-wrapper th,
.markdown-wrapper td {
  border: 1px solid #ddd;
  padding: 8px 12px;
}
</style>

3️⃣ 使用示例(豆包 / 元宝 / Dify 通用)

<template>
  <MarkdownRenderer :content="aiAnswer" />
</template>

<script setup>
import { ref, onMounted } from 'vue'
import axios from 'axios'

const aiAnswer = ref('')

onMounted(async () => {
  const res = await axios.post('/api/dify', {
    query: '介绍一下 Vue 渲染 Markdown'
  })

  aiAnswer.value = res.data.answer
})
</script>

四、Dify API 返回格式适配

Dify 常见返回:

{
  "answer": "## 结果\n\n```js\nconsole.log('hello')\n```"
}

✅ 直接用:

<MarkdownRenderer :content="res.data.answer" />

五、如何“保留原有样式”(关键)

✅ 方法 1:复用官方 CSS(最像原版)

来源

样式

GitHub

github.css

豆包

仿 Ant Design

元宝

类似腾讯文档

@import url("https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.3.0/github-markdown.min.css");
<div class="markdown-body">
  <MarkdownRenderer :content="text" />
</div>

✅ 方法 2:自定义 Token 映射(高级)

如果你想 完全还原某个平台的 UI

md.renderer.rules.heading_open = (tokens, idx) => {
  return `<h${tokens[idx].tag} class="custom-heading">`
}

六、安全处理(强烈建议)

npm install sanitize-html
import sanitizeHtml from 'sanitize-html'

renderedHtml.value = sanitizeHtml(
  md.render(props.content),
  {
    allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img']),
    allowedAttributes: {
      '*': ['class', 'style'],
      a: ['href', 'target']
    }
  }
)

七、最终推荐组合 ✅

场景

推荐

AI 对话

markdown-it + highlight.js

文档展示

github-markdown-css

富交互

自定义 token 规则

安全

sanitize-html


Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐