Skip to content

XMarkdown(独立包)

使用import { MarkdownRenderer } from 'x-markdown-vue' import 'x-markdown-vue/style'
文档
编辑此页更新日志Issue 反馈

💌 Info

v2.0.0 开始,vue-element-plus-x 不再内置 Markdown 渲染组件。如需 Markdown 渲染功能,请单独安装 x-markdown-vue

介绍

x-markdown-vue 是从 vue-element-plus-x 中抽离出来的独立 Markdown 渲染组件库,专为 AI 对话场景中的富文本展示与流式输出渲染而设计。

✨ 核心特性

  • 🚀 流式渲染 — 支持 AI 对话场景的实时输出动画,带逐字淡入效果
  • 📝 GitHub Flavored Markdown — 完整支持 GFM 语法(表格、任务列表等)
  • 🎨 代码高亮 — 基于 Shiki,支持 100+ 语言和多种主题,可按需禁用
  • 🧮 LaTeX 数学公式 — 支持行内 $...$ 与块级 $$...$$ 数学公式
  • 📊 Mermaid 图表 — 支持流程图、时序图、甘特图、类图等,可按需禁用
  • 🌗 深色模式 — 内置深浅色主题切换支持
  • 🔌 高度可定制 — 支持自定义渲染插槽、自定义属性、自定义代码块渲染器
  • 🎭 灵活插件系统 — 支持 remark 和 rehype 插件扩展
  • 🔒 安全可靠 — 可选的 HTML 内容清理,防止 XSS 攻击

v2.0.0 开始,组件库不再内置 Typewriter / XMarkdown / XMarkdownAsync,如需 Markdown 渲染,请单独安装并在业务侧集成。

安装

bash
# pnpm(推荐)
pnpm add x-markdown-vue

# npm
npm install x-markdown-vue

# yarn
yarn add x-markdown-vue

可选依赖

x-markdown-vue 采用按需加载策略,以下功能需要安装对应依赖:

bash
# 代码高亮(Shiki)
pnpm add shiki shiki-stream

# Mermaid 图表
pnpm add mermaid

# LaTeX 数学公式(还需引入 KaTeX 样式)
pnpm add katex

💡 Tip

如果不安装 shikishiki-stream,控制台可能会出现警告,代码块将降级为纯文本渲染。

代码演示

基础用法

加载中...

使用 MarkdownRenderer 渲染静态 Markdown 内容,支持 GFM、任务列表、表格、代码高亮等。

流式渲染动画

加载中...

开启 enable-animate 后,新增内容将以逐字淡入动画效果呈现,非常适合 AI 流式输出场景。

深色模式

浅色
加载中...

通过 is-dark prop 切换深浅色主题,代码块语法高亮主题也会随之自动切换。

代码块配置

最大高度:
加载中...

支持配置是否显示头部、最大高度、粘性头部等代码块相关选项。

搭配 BubbleList 使用粘性代码头部

MarkdownRenderer 放入 BubbleList#content 插槽,以 BubbleList 自身作为滚动容器。滚动时代码块头部吸附到 列表可视区顶部,不受页面导航栏遮挡。

💡 向下滚动列表,代码块顶部的语言标签将吸附到 BubbleList 可视区顶部,而非页面顶部。

MarkdownRenderer 放在 BubbleList#content 插槽中,以 BubbleList 自身作为滚动容器。滚动列表时,代码块顶部的语言标签与操作栏会吸附到 BubbleList 可视区域顶部,而非页面顶部,不受文档导航栏遮挡。

LaTeX 数学公式

需安装 katexpnpm add katex,并在入口引入样式:

ts
import 'katex/dist/katex.min.css';
加载中...

通过 enable-latex 启用数学公式渲染,需安装 katex 并引入其样式文件。

Mermaid 图表

需安装 mermaidpnpm add mermaid

加载中...

开启 enable-mermaid 后可渲染流程图、时序图等,需安装 mermaid

自定义代码块操作按钮

通过 code-block-actions 数组为代码块添加自定义操作按钮,支持 show 回调按语言条件显示。

onClick 回调接收的 CodeBlockSlotProps 参数:

属性类型说明
languagestring代码语言
codestring代码内容
copy(text: string) => void复制函数
copiedboolean是否已复制
collapsedboolean是否已折叠
toggleCollapse() => void切换折叠状态
加载中...

通过 code-block-actions 传入自定义按钮数组,可在代码块头部添加任意操作,按钮的 show 函数可控制其显示条件。

自定义 Mermaid 操作按钮

通过 mermaid-actions 数组为 Mermaid 图表工具栏添加自定义按钮。

onClick 回调接收的 MermaidSlotProps 参数:

属性类型说明
showSourceCodeboolean是否显示源码视图
svgstring渲染后的 SVG 字符串
rawContentstringMermaid 原始代码
isLoadingboolean是否正在渲染
zoomIn() => void放大
zoomOut() => void缩小
reset() => void重置缩放
fullscreen() => void全屏
toggleCode() => void切换源码/图表视图
copyCode() => Promise<void>复制源码
download() => void下载 SVG
加载中...

通过 mermaid-actions 传入自定义按钮数组,可在 Mermaid 图表工具栏添加自定义操作。

自定义代码块渲染器

加载中...

通过 code-x-render 对特定语言的代码块进行完全自定义渲染,适用于 JSON 可视化、图表渲染等场景。

自定义属性

加载中...

通过 custom-attrs 为特定 Markdown 元素添加 HTML 属性,如为链接添加 target="_blank"、为标题添加自定义 class 等。

自定义插槽

支持的插槽名称:

插槽名说明
heading / h1 ~ h6标题
code / inline-code / block-code代码
blockquote引用块
list / ul / ol / li / list-item列表
table / thead / tbody / tr / td / th表格
a链接
img图片
p / strong / em段落与行内元素
所有标准 HTML 标签名
加载中...

通过具名插槽自定义特定 Markdown 元素的渲染方式,可完全控制 HTML 输出结构和样式。

自定义表格(el-table 插槽)

通过 #table 插槽拦截 Markdown 中所有 GFM 表格,从插槽暴露的 hast node 中提取列和行数据,然后传入 el-table 渲染,获得排序、条纹、边框等完整能力。

加载中...

通过 #table 插槽拦截 Markdown 中的 GFM 表格。插槽暴露 children(一个返回 VNode 数组的函数),递归读取 <thead> / <tbody> 即可拿到列与行,再用 el-table 渲染获得边框、条纹等能力。

自定义代码块组件(el-table & my-echarts)

通过 code-x-render 自定义"语言标签",在 Markdown 中用围栏代码块声明 el-tablemy-echarts 语言,即可自动渲染为对应的 Vue 组件:

  • el-table — 解析 JSON { columns, rows } 并渲染为 Element Plus 表格
  • my-echarts — 解析 ECharts option JSON 并渲染为交互式图表
加载中...

通过 code-x-render 将特定语言的代码块渲染为 Vue 组件。本示例中:

  • el-table 语言块 — 将 JSON 数据渲染为 Element Plus 表格
  • my-echarts 语言块 — 将 ECharts JSON 配置渲染为交互式图表

插件系统

通过 remark-plugins / remark-plugins-ahead / rehype-plugins / rehype-plugins-ahead 扩展解析管道:

ts
import remarkEmoji from 'remark-emoji';
import rehypeSlug from 'rehype-slug';

// 在业务组件中传入
const remarkPlugins = [remarkEmoji];
const rehypePlugins = [rehypeSlug];
vue
<MarkdownRenderer
  :markdown="content"
  :remark-plugins="remarkPlugins"
  :rehype-plugins="rehypePlugins"
/>

安全配置

启用 sanitize 后,渲染前会清洗 HTML 内容,防止 XSS 注入:

vue
<MarkdownRenderer
  :markdown="content"
  :sanitize="true"
  :sanitize-options="{ allowedTags: ['b', 'i', 'em', 'strong', 'a'] }"
/>

流式自定义代码块(骨架屏占位)

模拟 AI 流式输出场景:JSON 拼接过程中显示 el-skeleton 骨架屏,等数据可解析后切换为对应的 el-table / el-form / my-echarts 真实组件。

加载中...

模拟 AI 流式输出的真实场景:当 `el-table` / `el-form` / `my-echarts` 代码块的 JSON 还在拼接中时,用 el-skeleton 骨架屏 占位;一旦 JSON 完整可解析,立刻切换为对应的真实组件回显。

判定方式:在 code-x-render 里尝试 JSON.parse(props.raw.content)解析失败 → 骨架屏;解析成功 → 真实组件,配合流式更新自然呈现"骨架屏 → 内容"的过渡。

API

Props

属性类型默认值说明
markdownstring''Markdown 文本内容
allow-htmlbooleanfalse是否允许 HTML 内容
enable-latexbooleantrue是否启用 LaTeX 数学公式
enable-animatebooleanfalse是否启用流式渲染动画
enable-breaksbooleantrue是否将单个换行转为 <br>
enable-gfmbooleantrue是否启用 GFM 语法
enable-shikibooleantrue是否启用 Shiki 代码高亮
enable-mermaidbooleantrue是否启用 Mermaid 图表
is-darkbooleanfalse是否为深色模式
shiki-theme[BuiltinTheme, BuiltinTheme]['vitesse-light', 'vitesse-dark']Shiki 浅色/深色主题
show-code-block-headerbooleantrue是否显示代码块头部
sticky-code-block-headerbooleanfalse代码块头部是否吸顶
code-max-heightstringundefined代码块最大高度,如 '300px'
code-block-actionsCodeBlockAction[][]代码块自定义操作按钮
mermaid-actionsMermaidAction[][]Mermaid 图表自定义操作按钮
mermaid-configobject{}Mermaid 初始化配置
code-x-renderobject{}自定义代码块渲染函数
custom-attrsCustomAttrs{}自定义元素属性
remark-pluginsPluggableList[]remark 插件列表(内置后运行)
remark-plugins-aheadPluggableList[]remark 插件列表(内置前运行)
rehype-pluginsPluggableList[]rehype 插件列表(内置后运行)
rehype-plugins-aheadPluggableList[]rehype 插件列表(内置前运行)
rehype-optionsobject{}rehype 处理器配置
sanitizebooleanfalse是否启用内容清洗(防 XSS)
sanitize-optionsSanitizeOptions{}内容清洗配置项

CodeBlockAction 类型

ts
interface CodeBlockAction {
  key: string;
  icon?: Component | FunctionalComponent | string;
  title?: string;
  onClick?: (props: CodeBlockSlotProps) => void;
  disabled?: boolean;
  class?: string;
  style?: Record<string, string>;
  show?: (props: CodeBlockSlotProps) => boolean;
}

MermaidAction 类型

ts
interface MermaidAction {
  key: string;
  icon?: Component | FunctionalComponent | string;
  title?: string;
  onClick?: (props: MermaidSlotProps) => void;
  disabled?: boolean;
  class?: string;
  style?: Record<string, string>;
  show?: (props: MermaidSlotProps) => boolean;
}