XMarkdown 渲染组件 📜
介绍
XMarkdown
这个组件内置了行内代码、代码块、数学公式函数(行/块)、mermaid 图表等基础样式。在这个开发文档中,有一些样式的演示可能不是很好,但是应该不会影响集成的使用。如果有集成或一些使用问题,可以进 👉交流群 获取最新的技术支持。
📌 注意
该组件支持增量更新,支持自定义。更多的样式内置和组件的自定义🥰
代码演示
基本使用
快速渲染一个 Markdown 基础的文本。内置了行内代码、代码块、数学公式函数(行/块)、mermaid 图表等基础样式。
📌 注意
支持增量更新,可以在控制台查看节点的更新变化。
<script setup lang="ts">
const markdown = ref(`
# 一级标题
## 二级标题
### 三级标题
#### 四级标题
##### 五级标题
###### 六级标题
**这是粗体文本**
__这也是粗体文本__
*这是斜体文本*
_这也是斜体文本_
***这是粗斜体文本***
~~这是带删除线的文本~~
- 无序列表项1
- 无序列表项2
- 子列表项2.1
- 子列表项2.2
1. 有序列表项1
2. 有序列表项2
1. 子列表项2.1
2. 子列表项2.2
[Element-Plus-X](https://element-plus-x.com "Element-Plus-X")

>这是一段引用文本
>
>> 这是嵌套的引用文本
---
| 姓名 | 年龄 | 职业 |
| ---- | ---- | ---- |
| 张三 | 25 | 工程师 |
| 李四 | 30 | 设计师 |
### 行内代码
用 \`ElmentPlusX\` 表示 行内块代码用 \`\` 语句
### 代码块
\`\`\`javascript
const code = "Element-Plus-X";
\`\`\`
### 行内公式
$e^{i\\pi} + 1 = 0$
### 块级公式
$$
F(\\omega) = \\int_{-\\infty}^{\\infty} f(t) e^{-i\\omega t} dt
$$
### mermaid 饼状图
\`\`\`mermaid
pie
"传媒及文化相关" : 35
"广告与市场营销" : 8
"游戏开发" : 15
"影视动画与特效" : 12
"互联网产品设计" : 10
"VR/AR开发" : 5
"其他" : 15
\`\`\`
`);
const timer = ref();
const index = ref(0);
const content = computed(() => {
return markdown.value.slice(0, index.value);
});
function start() {
timer.value = setInterval(() => {
index.value += 5;
if (index.value > markdown.value.length) {
clearInterval(timer.value);
index.value = markdown.value.length;
}
}, 100);
}
function pause() {
if (timer.value) {
clearInterval(timer.value);
timer.value = null;
}
}
function redo() {
index.value = 0;
if (timer.value) {
clearInterval(timer.value);
timer.value = null;
}
start();
}
onMounted(() => {
start();
});
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px">
<span style="font-size: 20px; font-weight: 700">控制台查看增量渲染</span>
<div style="display: flex; gap: 8px">
<el-button @click="start"> 开始 </el-button>
<el-button @click="pause"> 暂停 </el-button>
<el-button @click="redo"> 重新开始 </el-button>
</div>
<XMarkdown :markdown="content" />
</div>
</template>
<style scoped lang="less"></style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
覆盖样式
如果你集成该组件时,发现组件内置的样式变的奇怪。可能是你项目的内置全局样式,和这个组件的一些基础样式有冲突。那么你可以通过覆盖样式的方式来解决这个问题。
💌 消息
创建一个样式文件,例如:self-markdown.css
,并添加一些自定义样式内容:
.h1 {
font-size: 24px;
color: red;
margin-bottom: 16px;
}
2
3
4
5
将这个文件引入到你的项目,例如:
import 'self-markdown.css'
如果没有覆盖,大概率是因为你设置层级不够,可以尝试样式穿透
<script setup lang="ts">
const markdown = `
# 一级标题
## 二级标题
### 三级标题
`;
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px">
<XMarkdown :markdown="markdown" class="self-markdown-body" />
</div>
</template>
<style scoped lang="less">
.self-markdown-body {
:deep(h1) {
font-size: 24px;
color: red;
margin-bottom: 16px;
}
:deep(h2) {
margin: 0;
font-size: 20px;
color: blue;
margin-bottom: 16px;
}
}
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
github 样式
市场上也有很多优秀的作者,开源了他们的 markdown 样式,这里演示一个集成使用 github 样式的案例。
你可以直接下载 github-markdown.css 这个文件,或者把样式代码复制到自己的 css 文件中。然后在项目中引用。
📌 注意
不过值得注意的是,一般这种文件样式,都是被 markdown-body
类名包住的。光引入样式文件,是不行的。你可能还需要给 XMarkdown
添加一个类名,来让样式生效。这个类名和引入的样式文件中的最外层的类名,应该保持一致。
<script setup lang="ts">
// (假如你的样式文件存在)引入样式文件
// import "./github-markdown.css"
const markdown = `
# 一级标题
## 二级标题
### 三级标题
`;
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px">
<!-- 这里设置类名,让 github 样式生效 -->
<XMarkdown :markdown="markdown" class="markdown-body" />
</div>
</template>
<style scoped lang="less"></style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
allowHtml
支持 html 标签渲染,使用 allowHtml
属性开启,默认开启。
<script setup lang="ts">
const markdown = `<div style="color: red;">这是一个 html 标签测试。</div>`;
const value1 = ref(true);
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px">
<el-switch v-model="value1" />
<XMarkdown :markdown="markdown" :allow-html="value1" />
</div>
</template>
<style scoped lang="less"></style>
2
3
4
5
6
7
8
9
10
11
12
13
enableLatex
支持 latex 数学公式渲染,使用 enableLatex
属性开启,默认开启。
<script setup lang="ts">
const markdown = `
### 行内公式
$e^{i\\pi} + 1 = 0$
### 块级公式
$$
F(\\omega) = \\int_{-\\infty}^{\\infty} f(t) e^{-i\\omega t} dt
$$
`;
const value1 = ref(true);
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px">
<el-switch v-model="value1" />
<XMarkdown :markdown="markdown" :enable-latex="value1" />
</div>
</template>
<style scoped lang="less"></style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
enableBreaks
支持 remark-breaks 渲染,使用 enableBreaks
属性开启,默认开启。
支持硬中断而不需要空格或转义符(将回车符变成 <br>
)。让你的内容渲染更加还原。
<script setup lang="ts">
const markdown = `Mars is
the fourth planet`;
const value1 = ref(true);
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px">
<el-switch v-model="value1" />
<XMarkdown :markdown="markdown" :enable-breaks="value1" />
</div>
</template>
<style scoped lang="less"></style>
2
3
4
5
6
7
8
9
10
11
12
13
14
自定义代码块渲染
使用 codeXRender
属性,自定义代码块的渲染。这个属性接受一个对象,对象中的 key 为代码块的语言,value 为一个函数,函数的参数为代码块的属性,返回值为一个 VNode。意味着你可以用 Vue 的模板语法来渲染代码块。
📌 注意
这个功能会拦截你设置的代码块,你可以和后端商量好码块的语言,然后根据语言返回一个对应的 VNode。
后续我们会打造一个基于这个组件的组件库广场,如果你对此感兴趣,欢迎加入🥰交流群,或者添加作者联系方式,一同打造这个广场项目。🥳敬请期待
<script setup lang="ts">
import { h } from 'vue';
import Echarts from './echarts.vue';
const markdown = `
\`\`\`javascript
const a = 1;
\`\`\`
\`\`\`echarts
option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
data: [150, 230, 224, 218, 135, 147, 260],
type: 'line'
}
]
};
\`\`\`
`;
const selfCodeXRender = {
// 渲染自定义代码块标识符 javascript, 返回一个组件
javascript: (props: { raw: any }) => {
return h(
'pre',
{ class: 'language-javascript' },
h('code', { class: 'language-javascript' }, props.raw.content)
);
},
// 渲染自定义代码块标识符 echarts, Echarts 是自己封装的Vue组件
echarts: (props: { raw: any }) => h(Echarts, { code: props.raw.content })
};
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px">
<XMarkdown :markdown="markdown" :code-x-render="selfCodeXRender" />
</div>
</template>
<style scoped lang="less"></style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
自定义代码块顶部渲染
如果你仅仅想修改我们内置的代码块顶部的内容,你可以使用 codeXSlot
。并且我们暴露出来了内置的 折叠
、主题切换
、复制
方法。你可以在仅改变样式的同时,保留默认功能。
使用 codeXSlot
属性,自定义代码块顶部插槽的渲染。这个属性接受一个对象,对象中的 key 为 CodeBlockHeaderExpose 这个类型的固定的属性,value 为一个函数,函数的参数为代码块的属性,返回值为一个 VNode,意味着你可以用 Vue 的模板语法来渲染代码块的顶部。
你可以在自定义的模版中获取到 props, 并且 props 中有以下属性 (具体属性可以在项目中自行打印查看):
toggleExpand
: props.toggleExpand 展开代码块。isDark
: props.isDark.value 获取当前代码块主题。toggleTheme
: props.toggleTheme 切换代码块主题。renderLines
: props.renderLines 获取这个代码块的内容,你可以用它来传给复制函数。copyCode
: props.copyCode() 复制代码块(需要传参)。
以下是 mermaid 的代码块头部自定义组件 props 中有可以获取的内置属性:
zoomIn
: props.zoomIn 放大。zoomOut
: props.zoomOut 缩小。reset
: props.reset 回到初始位置。toggleCode
: props.toggleCode 切换显示代码。download
: props.download 下载图片。fullscreen
: props.fullscreen 进入全屏。copyCode
: props.copyCode 复制代码。
// 这个属性的类型定义
interface CodeBlockHeaderExpose {
// 自定义渲染整个代码块的头部
codeHeader?: CodeBlockHeaderRenderer;
// 自定义渲染代码块的左侧语言标识符
codeHeaderLanguage?: CodeBlockHeaderRenderer;
// 自定义渲染代码块的右侧控制按钮
codeHeaderControl?: CodeBlockHeaderRenderer;
// 自定义渲染 mermaid 顶部插槽
codeMermaidHeaderControl?: CodeBlockHeaderRenderer;
}
2
3
4
5
6
7
8
9
10
11
<script setup lang="ts">
// 这个 ts 类型还未成功导出,还有 props 类型目前暂时使用 any,需要后续优化
// import type { CodeBlockHeaderExpose, CodeBlockExpose } from 'vue-element-plus-x/types/components/XMarkdownCore/components/CodeBlock/shiki-header.d.ts';
import { h } from 'vue';
const markdown = `
\`\`\`javascript
const a = 1;
\`\`\`
`;
const mermaidMarkdown = `
\`\`\`mermaid
pie
"传媒及文化相关" : 35
"广告与市场营销" : 8
"游戏开发" : 15
"影视动画与特效" : 12
"互联网产品设计" : 10
"VR/AR开发" : 5
"其他" : 15
\`\`\`
`;
// 如果你是用了codeHeader 属性,其他两个属性失效
const selfCodeXSlot1 = {
// 自定义渲染整个代码块的头部
codeHeader: (props: any) =>
h(
'div',
{
onClick: (ev: MouseEvent) => props.toggleExpand(ev)
},
{ default: () => '这是自定义头部,点击切换折叠状态' }
),
// 自定义渲染代码块的左侧语言标识符
codeHeaderLanguage: () => h('div', '自定义代码块左侧语言标识符'),
// 自定义渲染代码块的右侧控制按钮
codeHeaderControl: () => h('div', '自定义代码块右侧控制按钮')
};
// 如果你是用了codeHeader 属性,其他两个属性失效
const selfCodeXSlot2 = {
// 自定义渲染代码块的左侧语言标识符
codeHeaderLanguage: () => h('div', '自定义代码块左侧语言标识符')
};
const selfCodeXSlot3 = {
// 自定义渲染代码块的右侧控制按钮
codeHeaderControl: () => h('div', '自定义代码块右侧控制按钮')
};
// 如果你是用了codeHeader 属性,其他两个属性失效
const selfCodeXSlot4 = {
codeMermaidHeaderControl: (props: any) => {
return h(
'div',
{
style: {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '12px 16px',
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
color: 'white',
borderRadius: '8px',
boxShadow: '0 4px 12px rgba(102, 126, 234, 0.3)'
}
},
[
h(
'div',
{
style: { display: 'flex', alignItems: 'center', gap: '12px' }
},
[
h('span', { style: { fontSize: '16px' } }, '🎨'),
h('span', { style: { fontWeight: '600' } }, 'Custom Mermaid'),
h(
'span',
{
style: {
fontSize: '12px',
background: 'rgba(255,255,255,0.25)',
padding: '4px 8px',
borderRadius: '12px'
}
},
props.showSourceCode ? '📝 源码' : '📊 图表'
)
]
),
h('div', { style: { display: 'flex' } }, [
h(
ElTooltip,
{
content: '放大',
placement: 'top'
},
{
default: () =>
h(
ElButton,
{
size: 'small',
type: 'primary',
text: true,
bg: true,
style: {
background: 'rgba(255,255,255,0.2)',
color: 'white',
border: 'none'
},
onClick: props.zoomIn
},
() => '🔍'
)
}
),
h(
ElTooltip,
{
content: '重置缩放',
placement: 'top'
},
{
default: () =>
h(
ElButton,
{
size: 'small',
type: 'primary',
text: true,
bg: true,
style: {
background: 'rgba(255,255,255,0.2)',
color: 'white',
border: 'none'
},
onClick: props.reset
},
() => '🔄'
)
}
),
h(
ElTooltip,
{
content: props.showSourceCode ? '查看图表' : '查看源码',
placement: 'top'
},
{
default: () =>
h(
ElButton,
{
size: 'small',
type: 'primary',
text: true,
bg: true,
style: {
background: 'rgba(255,255,255,0.2)',
color: 'white',
border: 'none'
},
onClick: props.toggleCode
},
() => (props.showSourceCode ? '👁️' : '📝')
)
}
),
h(
ElTooltip,
{
content: '自定义复制',
placement: 'top'
},
{
default: () =>
h(
ElButton,
{
size: 'small',
type: 'primary',
text: true,
bg: true,
style: {
background: 'rgba(255,255,255,0.2)',
color: 'white',
border: 'none'
},
// 🎯 用户自定义复制逻辑演示 - 完全接管
onClick: async () => {
try {
const customContent = `🎨 自定义前缀:\n\n${props.rawContent}\n\n📝 来自:Element-Plus-X`;
await navigator.clipboard.writeText(customContent);
ElMessage.success('🎉 组件插槽自定义复制成功!');
} catch (err) {
console.error('❌ 自定义复制失败:', err);
}
}
},
() => '📋'
)
}
),
h(
ElTooltip,
{
content: '下载图片',
placement: 'top'
},
{
default: () =>
h(
ElButton,
{
size: 'small',
type: 'primary',
text: true,
bg: true,
style: {
background: 'rgba(255,255,255,0.2)',
color: 'white',
border: 'none'
},
onClick: props.download
},
() => '💾'
)
}
)
])
]
);
}
};
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px">
<XMarkdown :markdown="markdown" :code-x-slot="selfCodeXSlot1" />
<XMarkdown :markdown="markdown" :code-x-slot="selfCodeXSlot2" />
<XMarkdown :markdown="markdown" :code-x-slot="selfCodeXSlot3" />
<XMarkdown :markdown="mermaidMarkdown" :code-x-slot="selfCodeXSlot4" />
</div>
</template>
<style scoped lang="less"></style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
自定义属性
使用 customAttrs
属性,接收一个对象,对象中的属性为标签名,值为标签的属性。匹配一个标签,就会给该标签添加相应的属性。
<script setup lang="ts">
const markdown = `
<a href="https://element-plus-x.com/">element-plus-x</a>
<h1>标题1</h1>
<h2>标题2</h2>
<self-btn>给自定义标签添加 el-button 类名</self-btn>
`;
// 如果你是用了codeHeader 属性,其他两个属性失效
const selfAttrs = {
a: () => ({
target: '_blank',
rel: 'noopener noreferrer'
}),
h1: {
style: {
color: 'red',
fontSize: '24px'
}
},
h2: {
style: {
color: 'blue',
fontSize: '20px'
}
},
// 给自定义标签添加 el-button 类名
'self-btn': {
class: 'el-button'
}
};
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px">
<XMarkdown :markdown="markdown" :custom-attrs="selfAttrs" />
</div>
</template>
<style scoped lang="less"></style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
mermaid 配置
使用 mermaidConfig
属性,自定义mermaid 顶部的 ToolbarConfig 。这个属性接受一个MermaidToolbarConfig 对象, 可以控制顶部控件的隐藏展示,一些类名的添加,还有悬停颜色的控制。
📌 注意
如果你和 code-x-slot
设置了 codeMermaidHeaderControl
属性,则完全接管 mermaid 的 Toolbar 插槽,由开发者完全自定义。当然,我们还是暴露了内置的 Toolbar 方法,你可以仅修改样式的情况下,保留一些内置的你需要的方法。
interface MermaidToolbarConfig {
showToolbar?: boolean;
showFullscreen?: boolean;
showZoomIn?: boolean;
showZoomOut?: boolean;
showReset?: boolean;
showDownload?: boolean;
toolbarStyle?: Record<string, any>;
toolbarClass?: string;
iconColor?: string;
tabTextColor?: string;
hoverBackgroundColor?: string;
tabActiveBackgroundColor?: string;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
<script setup lang="ts">
import { ElButton, ElMessage, ElTooltip } from 'element-plus';
import { h } from 'vue';
const markdown = `
\`\`\`mermaid
pie
"传媒及文化相关" : 35
"广告与市场营销" : 8
"游戏开发" : 15
"影视动画与特效" : 12
"互联网产品设计" : 10
"VR/AR开发" : 5
"其他" : 15
\`\`\`
`;
const selfCodeXSlot = {
codeMermaidHeaderControl: (props: any) => {
return h(
'div',
{
style: {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '12px 16px',
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
color: 'white',
borderRadius: '8px',
boxShadow: '0 4px 12px rgba(102, 126, 234, 0.3)'
}
},
[
h(
'div',
{
style: { display: 'flex', alignItems: 'center', gap: '12px' }
},
[
h('span', { style: { fontSize: '16px' } }, '🎨'),
h('span', { style: { fontWeight: '600' } }, 'Custom Mermaid'),
h(
'span',
{
style: {
fontSize: '12px',
background: 'rgba(255,255,255,0.25)',
padding: '4px 8px',
borderRadius: '12px'
}
},
props.showSourceCode ? '📝 源码' : '📊 图表'
)
]
),
h('div', { style: { display: 'flex' } }, [
h(
ElTooltip,
{
content: '放大',
placement: 'top'
},
{
default: () =>
h(
ElButton,
{
size: 'small',
type: 'primary',
text: true,
bg: true,
style: {
background: 'rgba(255,255,255,0.2)',
color: 'white',
border: 'none'
},
onClick: props.zoomIn
},
() => '🔍'
)
}
),
h(
ElTooltip,
{
content: '重置缩放',
placement: 'top'
},
{
default: () =>
h(
ElButton,
{
size: 'small',
type: 'primary',
text: true,
bg: true,
style: {
background: 'rgba(255,255,255,0.2)',
color: 'white',
border: 'none'
},
onClick: props.reset
},
() => '🔄'
)
}
),
h(
ElTooltip,
{
content: props.showSourceCode ? '查看图表' : '查看源码',
placement: 'top'
},
{
default: () =>
h(
ElButton,
{
size: 'small',
type: 'primary',
text: true,
bg: true,
style: {
background: 'rgba(255,255,255,0.2)',
color: 'white',
border: 'none'
},
onClick: props.toggleCode
},
() => (props.showSourceCode ? '👁️' : '📝')
)
}
),
h(
ElTooltip,
{
content: '自定义复制',
placement: 'top'
},
{
default: () =>
h(
ElButton,
{
size: 'small',
type: 'primary',
text: true,
bg: true,
style: {
background: 'rgba(255,255,255,0.2)',
color: 'white',
border: 'none'
},
// 🎯 用户自定义复制逻辑演示 - 完全接管
onClick: async () => {
try {
const customContent = `🎨 自定义前缀:\n\n${props.rawContent}\n\n📝 来自:Element-Plus-X`;
await navigator.clipboard.writeText(customContent);
ElMessage.success('🎉 组件插槽自定义复制成功!');
} catch (err) {
console.error('❌ 自定义复制失败:', err);
}
}
},
() => '📋'
)
}
),
h(
ElTooltip,
{
content: '下载图片',
placement: 'top'
},
{
default: () =>
h(
ElButton,
{
size: 'small',
type: 'primary',
text: true,
bg: true,
style: {
background: 'rgba(255,255,255,0.2)',
color: 'white',
border: 'none'
},
onClick: props.download
},
() => '💾'
)
}
)
])
]
);
}
};
const selfMermaidConfig = {
showToolbar: true,
showFullscreen: false,
showZoomIn: true,
showZoomOut: true,
showReset: true,
showDownload: false,
toolbarStyle: {
background: 'linear-gradient(135deg, #8b5cf6 0%, #a855f7 100%)',
boxShadow: '0 4px 16px rgba(139, 92, 246, 0.3)',
borderRadius: '8px'
},
iconColor: '#FFFFFF',
tabTextColor: '#FFFFFF'
};
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px">
<XMarkdown
:markdown="markdown"
:code-x-slot="selfCodeXSlot"
:mermaid-config="selfMermaidConfig"
/>
<XMarkdown :markdown="markdown" :mermaid-config="selfMermaidConfig" />
</div>
</template>
<style scoped lang="less"></style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
插槽 标签拦截
你可以拦截一些标签,也可以是自定义的标签,然后自定义去渲染这些标签。如果是想自定义渲染图片或者视频,说不定会很方便
<script setup lang="ts">
const markdown = `
<img src="https://avatars.githubusercontent.com/u/76239030?v=4" alt="">
<self-btn>自定义标签</self-btn>
`;
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px">
<XMarkdown :markdown="markdown">
<template #img="{ ...props }">
<img :key="props.key" :src="props.src" style="border-radius: 30px" />
</template>
<template #self-btn="{ ...props }">
<el-button :key="props.key">
控制台查看 props 打印{{ console.log(props) }}
</el-button>
</template>
</XMarkdown>
</div>
</template>
<style scoped lang="less"></style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
属性
属性名 | 类型 | 是否必填 | 默认值 | 描述 |
---|---|---|---|---|
markdown | string | 是 | '' | markdown 内容 |
allowHtml | bool | 否 | true | 是否渲染 html |
enableLatex | bool | 否 | true | 是否渲染 latex |
enableBreaks | bool | 否 | true | 是否渲染 breaks |
codeXRender | Object | 否 | ()=>{} | 自定义代码块渲染 |
codeXSlot | Object | 否 | ()=>{} | 自定义代码块顶部插槽渲染 |
customAttrs | Object | 否 | ()=>{} | 自定义属性 |
mermaidConfig | Object | 否 | ()=>{} | mermaid 配置 |
功能特性
- 支持增量渲染,极致的性能
- 支持自定义插槽,可以是 h 函数的组件,也可以是 template 模版组件。上手更简单
- 内置丰富的基础样式数学公式,mermaid图表,减少开发者负担
- 支持多种拦截,和自定义渲染,上限拉满