- 🚀 Vue 3 组合式 API - 基于 Vue 3 Composition API 构建
- 📝 GitHub Flavored Markdown - 完整支持 GFM 语法
- 🎨 代码高亮 - 基于 Shiki,支持 100+ 语言和多种主题
- 🌊 流式渲染 - 支持 AI 对话场景的实时输出动画
- 🧮 LaTeX 数学公式 - 支持行内和块级数学公式渲染
- 📊 Mermaid 图表 - 支持流程图、时序图等多种图表
- 🌗 深色模式 - 内置深浅色主题切换支持
- 🔌 高度可定制 - 支持自定义渲染、插槽和属性
- 🎭 灵活的插件系统 - 支持 remark 和 rehype 插件扩展
- 🔒 安全可靠 - 可选的 HTML 内容清理和消毒
- 📦 Monorepo 架构 - 使用 pnpm workspace 和 Turbo 管理
# pnpm (推荐)
pnpm add x-markdown-vue
# npm
npm install x-markdown-vue
# yarn
yarn add x-markdown-vue确保安装了对等依赖:
pnpm add vue@^3.3.0如果需要 LaTeX 支持,还需要引入 KaTeX 样式:
import 'katex/dist/katex.min.css'<template>
<MarkdownRenderer :markdown="content" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { MarkdownRenderer } from 'x-markdown-vue'
import 'x-markdown-vue/style'
const content = ref(`
# Hello World
This is a **markdown** renderer.
`)
</script>对于大型文档,可以使用异步渲染模式:
<template>
<Suspense>
<MarkdownRendererAsync :markdown="content" />
<template #fallback>
<div>加载中...</div>
</template>
</Suspense>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { MarkdownRendererAsync } from 'x-markdown-vue'
import 'x-markdown-vue/style'
const content = ref('# Large Document\n...')
</script>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
markdown |
string |
'' |
Markdown 字符串内容 |
allowHtml |
boolean |
false |
是否允许渲染 HTML |
enableLatex |
boolean |
true |
是否启用 LaTeX 数学公式支持 |
enableAnimate |
boolean |
false |
是否启用流式动画效果 |
enableBreaks |
boolean |
true |
是否将换行符转换为 <br> |
isDark |
boolean |
false |
是否为深色模式 |
showCodeBlockHeader |
boolean |
true |
是否显示代码块头部 |
codeMaxHeight |
string |
undefined |
代码块最大高度,如 '300px' |
codeBlockActions |
CodeBlockAction[] |
[] |
代码块自定义操作按钮 |
mermaidActions |
MermaidAction[] |
[] |
Mermaid 图表自定义操作按钮 |
codeXRender |
object |
{} |
自定义代码块渲染函数 |
customAttrs |
CustomAttrs |
{} |
自定义属性对象 |
remarkPlugins |
PluggableList |
[] |
remark 插件列表 |
rehypePlugins |
PluggableList |
[] |
rehype 插件列表 |
sanitize |
boolean |
false |
是否启用内容清洗 |
sanitizeOptions |
SanitizeOptions |
{} |
清洗配置选项 |
interface CodeXProps {
codeLightTheme?: string // 亮色主题,默认 'vitesse-light'
codeDarkTheme?: string // 暗色主题,默认 'vitesse-dark'
showCodeBlockHeader?: boolean // 是否显示代码块头部
codeMaxHeight?: string // 代码块最大高度,如 '300px'
enableAnimate?: boolean // 是否启用代码块动画
codeBlockActions?: CodeBlockAction[] // 代码块自定义操作按钮
mermaidActions?: MermaidAction[] // Mermaid 图表自定义操作按钮
}
interface CodeBlockAction {
key: string // 唯一标识符
title: string // 按钮标题
icon: string // 按钮图标(SVG 或文本)
onClick: (props: any) => void // 点击回调函数
show?: (props: any) => boolean // 条件显示函数(可选)
}
interface MermaidAction {
key: string // 唯一标识符
title: string // 按钮标题
icon: string // 按钮图标(SVG 或文本)
onClick: (props: any) => void // 点击回调函数
show?: (props: any) => boolean // 条件显示函数(可选)
}<MarkdownRenderer
:markdown="content"
:is-dark="isDark"
:code-x-props="{
codeLightTheme: 'github-light',
codeDarkTheme: 'github-dark',
showCodeBlockHeader: true,
codeMaxHeight: '400px'
}"
/>通过 isDark 属性控制整体主题:
<template>
<MarkdownRenderer :markdown="content" :is-dark="isDark" />
</template>
<script setup>
import { ref } from 'vue'
const isDark = ref(false)
const toggleTheme = () => {
isDark.value = !isDark.value
}
</script>支持所有 Shiki 内置主题:
<MarkdownRenderer
:markdown="content"
:code-x-props="{
codeLightTheme: 'github-light',
codeDarkTheme: 'one-dark-pro'
}"
/>通过 customAttrs 为 Markdown 元素添加自定义属性:
<MarkdownRenderer
:markdown="content"
:custom-attrs="{
heading: (node, { level }) => ({
class: ['heading', `heading-${level}`],
id: `heading-${level}`
}),
a: (node) => ({
target: '_blank',
rel: 'noopener noreferrer'
})
}"
/>组件提供了强大的插槽系统,可以自定义任何 Markdown 元素的渲染:
<MarkdownRenderer :markdown="content">
<!-- 自定义标题渲染 -->
<template #heading="{ node, level, children }">
<component :is="`h${level}`" class="custom-heading">
<a :href="`#heading-${level}`" class="anchor">#</a>
<component :is="children" />
</component>
</template>
<!-- 自定义引用块渲染 -->
<template #blockquote="{ children }">
<blockquote class="custom-blockquote">
<div class="quote-icon">💬</div>
<component :is="children" />
</blockquote>
</template>
<!-- 自定义链接渲染 -->
<template #a="{ node, children }">
<a :href="node?.properties?.href" target="_blank" class="custom-link">
<component :is="children" />
<span class="external-icon">↗</span>
</a>
</template>
</MarkdownRenderer>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 标签名
通过 codeXRender 自定义特定语言的代码块渲染:
<script setup>
import { h } from 'vue'
import EchartsRenderer from './EchartsRenderer.vue'
const codeXRender = {
// 自定义 echarts 代码块渲染
echarts: (props) => h(EchartsRenderer, { code: props.raw.content }),
// 自定义行内代码渲染
inline: (props) => h('code', { class: 'custom-inline' }, props.raw.content)
}
</script>
<template>
<MarkdownRenderer :markdown="content" :code-x-render="codeXRender" />
</template>通过 codeXSlots 自定义代码块的头部区域:
<script setup>
import { h } from 'vue'
const codeXSlots = {
'header-left': ({ language }) => h('span', { class: 'lang-badge' }, language),
'header-right': ({ code, copy }) => h('button', { onClick: () => copy(code) }, '📋 复制')
}
</script>
<template>
<MarkdownRenderer :markdown="content" :code-x-slots="codeXSlots" />
</template>启用 enableAnimate 属性后,代码块中的每个 token 会添加 x-md-animated-word class,可配合 CSS 实现流式输出动画效果:
<MarkdownRenderer :markdown="content" :enable-animate="true" />/* 自定义动画样式 */
.x-md-animated-word {
animation: fadeIn 0.3s ease-in-out;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}<script setup>
import remarkEmoji from 'remark-emoji'
const remarkPlugins = [remarkEmoji]
</script>
<template>
<MarkdownRenderer :markdown="content" :remark-plugins="remarkPlugins" />
</template><script setup>
import rehypeSlug from 'rehype-slug'
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
const rehypePlugins = [rehypeSlug, rehypeAutolinkHeadings]
</script>
<template>
<MarkdownRenderer :markdown="content" :rehype-plugins="rehypePlugins" />
</template>启用内容清洗以防止 XSS 攻击:
<MarkdownRenderer
:markdown="untrustedContent"
:sanitize="true"
:sanitize-options="{
allowedTags: ['h1', 'h2', 'p', 'a', 'code', 'pre'],
allowedAttributes: {
a: ['href', 'target']
}
}"
/>支持 100+ 编程语言的语法高亮,基于 Shiki 引擎:
```javascript
function greet(name) {
console.log(`Hello, ${name}!`);
}
```
```python
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
```支持行内和块级数学公式:
行内公式: $E = mc^2$
块级公式:
$$
\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}
$$X-Markdown 支持完整的 Mermaid 图表渲染,包括流程图、时序图、甘特图、类图、状态图、饼图、ER 图等多种图表类型,并提供丰富的交互功能。
graph TB
A[开始] --> B{是否登录?}
B -->|是| C[进入首页]
B -->|否| D[跳转登录页]
D --> E[输入账号密码]
E --> F{验证通过?}
F -->|是| C
F -->|否| G[显示错误]
G --> E
C --> H[结束]
sequenceDiagram
participant U as 用户
participant C as 客户端
participant S as 服务器
participant D as 数据库
U->>C: 点击登录
C->>S: POST /api/login
S->>D: 查询用户信息
D-->>S: 返回用户数据
S-->>C: 返回 JWT Token
C-->>U: 登录成功,跳转首页
gantt
title 项目开发计划
dateFormat YYYY-MM-DD
section 需求分析
需求调研 :a1, 2024-01-01, 7d
需求文档 :after a1, 5d
section 设计阶段
UI 设计 :2024-01-10, 10d
架构设计 :2024-01-12, 8d
section 开发阶段
前端开发 :2024-01-20, 20d
后端开发 :2024-01-20, 25d
section 测试上线
集成测试 :2024-02-15, 10d
上线部署 :2024-02-25, 3d
classDiagram
class Animal {
+String name
+int age
+makeSound()
}
class Dog {
+String breed
+bark()
+fetch()
}
class Cat {
+String color
+meow()
+scratch()
}
class Bird {
+float wingspan
+fly()
+sing()
}
Animal <|-- Dog
Animal <|-- Cat
Animal <|-- Bird
stateDiagram-v2
[*] --> 待处理
待处理 --> 处理中 : 开始处理
处理中 --> 已完成 : 处理成功
处理中 --> 失败 : 处理失败
失败 --> 处理中 : 重试
失败 --> 已取消 : 取消
已完成 --> [*]
已取消 --> [*]
pie showData
title 技术栈使用占比
"Vue.js" : 35
"React" : 30
"Angular" : 15
"Svelte" : 10
"其他" : 10
erDiagram
USER ||--o{ ORDER : places
USER {
int id PK
string name
string email
}
ORDER ||--|{ ORDER_ITEM : contains
ORDER {
int id PK
date created_at
int user_id FK
}
ORDER_ITEM }|--|| PRODUCT : references
ORDER_ITEM {
int id PK
int quantity
int order_id FK
int product_id FK
}
PRODUCT {
int id PK
string name
float price
}
<template>
<MarkdownRenderer
:markdown="content"
:is-dark="isDark"
:enable-animate="true"
:code-x-props="{
codeLightTheme: 'github-light',
codeDarkTheme: 'github-dark',
showCodeBlockHeader: true,
codeMaxHeight: '400px',
enableAnimate: true,
codeBlockActions: [
{
key: 'run',
title: '运行代码',
icon: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8 5v14l11-7L8 5z" fill="currentColor"/></svg>',
onClick: (props) => {
console.log('运行代码:', props.code)
alert('运行代码功能(示例)')
},
show: (props) => ['javascript', 'typescript', 'js', 'ts'].includes(props.language)
}
],
mermaidActions: [
{
key: 'edit',
title: '编辑图表',
icon: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>',
onClick: (props) => {
console.log('编辑图表:', props.rawContent)
alert('编辑图表功能(示例)')
}
}
]
}"
:code-x-render="codeXRender"
/>
</template>
<script setup>
// 自定义渲染器配置
const codeXRender = {
json: ({ content, isDark }) => {
try {
const json = JSON.parse(content)
return `<div class="json-viewer" style="background: ${isDark ? '#1e1e1e' : '#f5f5f5'}; padding: 12px; border-radius: 4px; font-family: monospace; white-space: pre-wrap;">${JSON.stringify(json, null, 2)}</div>`
} catch {
return `<div style="color: red;">JSON 解析错误</div>`
}
},
echarts: ({ content, isDark }) => {
try {
const config = JSON.parse(content)
const chartId = 'chart-' + Math.random().toString(36).substr(2, 9)
return `<div id="${chartId}" style="height: 300px;"></div>
<script>
setTimeout(() => {
const chart = echarts.init(document.getElementById('${chartId}'), '${isDark ? 'dark' : 'default'}')
chart.setOption(${JSON.stringify(config)})
}, 100)
<\/script>`
} catch {
return `<div style="color: red;">ECharts 配置错误</div>`
}
}
}
</script>支持 GFM 表格语法:
| 特性 | 状态 |
|------|------|
| Markdown | ✅ |
| 代码高亮 | ✅ |
| LaTeX | ✅ |
| Mermaid | ✅ |- [x] 支持基础 Markdown
- [x] 添加语法高亮
- [x] 实现 LaTeX 支持
- [x] 添加 Mermaid 图表
- [ ] 更多功能开发中...- AI 对话应用 - 支持流式渲染,适合 ChatGPT 类应用
- 技术文档站点 - 完整的 Markdown 支持,代码高亮
- 博客系统 - 丰富的格式支持和自定义能力
- 在线编辑器 - 实时预览 Markdown 内容
- 知识库系统 - 支持数学公式和图表
- Vue 3 - 渐进式 JavaScript 框架
- TypeScript - 类型安全的 JavaScript 超集
- Unified - Markdown/HTML 处理生态系统
- Shiki - 语法高亮引擎
- KaTeX - 数学公式渲染
- Mermaid - 图表生成
- DOMPurify - HTML 清理工具
- Vite - 下一代前端构建工具
- Turbo - 高性能构建系统
x-markdown/
├── packages/
│ ├── x-markdown/ # 核心组件库
│ │ ├── src/
│ │ │ ├── components/ # Vue 组件
│ │ │ │ ├── CodeBlock/ # 代码块组件
│ │ │ │ ├── CodeLine/ # 行内代码组件
│ │ │ │ ├── CodeX/ # 代码渲染调度器
│ │ │ │ └── Mermaid/ # Mermaid 图表组件
│ │ │ ├── core/ # 核心渲染逻辑
│ │ │ ├── hooks/ # 组合式函数
│ │ │ ├── plugins/ # 内置插件
│ │ │ └── MarkdownRender/ # 主渲染组件
│ │ └── package.json
│ └── playground/ # 演示应用
├── pnpm-workspace.yaml
├── turbo.json
└── package.json
欢迎提交 Issue 和 Pull Request!
- Fork 本仓库
- 创建你的特性分支 (
git checkout -b feature/AmazingFeature) - 提交你的改动 (
git commit -m 'Add some AmazingFeature') - 推送到分支 (
git push origin feature/AmazingFeature) - 提交 Pull Request
# 克隆仓库
git clone https://github.com/element-plus-x/x-markdown.git
cd x-markdown
# 安装依赖
pnpm install
# 启动开发服务器
pnpm dev
# 构建项目
pnpm build
# 格式化代码
pnpm formatMIT License © 2025 element-plus-x
如果这个项目对你有帮助,请给它一个 ⭐️