5.3 KiB
5.3 KiB
Markdown渲染Skill
适用场景
当前端页面需要渲染Markdown格式的文本内容时使用,适用于:
- 日志详情展示
- 文章内容展示
- 备注/说明信息展示
实现方案
使用纯JavaScript实现简单的Markdown渲染,无需引入第三方库。
Vue 3 组件实现
<script setup lang="ts">
import { computed } from 'vue'
const props = defineProps<{
content?: string
}>()
const renderedContent = computed(() => {
if (!props.content) return '<p class="empty-content">暂无内容</p>'
let content = props.content
// 1. 转义HTML特殊字符(安全第一)
content = content
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
// 2. 标题(按优先级从高到低)
content = content.replace(/^### (.+)$/gm, '<h3>$1</h3>')
content = content.replace(/^## (.+)$/gm, '<h2>$1</h2>')
content = content.replace(/^# (.+)$/gm, '<h1>$1</h1>')
// 3. 粗体和斜体
content = content.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
content = content.replace(/\*(.+?)\*/g, '<em>$1</em>')
// 4. 代码块(多行)和行内代码
content = content.replace(/```(\w*)\n([\s\S]*?)```/g, '<pre><code class="language-$1">$2</code></pre>')
content = content.replace(/`(.+?)`/g, '<code>$1</code>')
// 5. 列表
content = content.replace(/^- (.+)$/gm, '<li>$1</li>')
content = content.replace(/(<li>.*<\/li>\n?)+/g, '<ul>$&</ul>')
content = content.replace(/^\d+\. (.+)$/gm, '<li>$1</li>')
// 6. 段落和换行
content = content.replace(/\n\n/g, '</p><p>')
content = content.replace(/\n/g, '<br>')
return `<p>${content}</p>`
})
</script>
<template>
<div class="markdown-body" v-html="renderedContent"></div>
</template>
样式规范
管理后台(Element Plus)
.markdown-body {
font-size: 14px;
line-height: 1.8;
color: #303133;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3 {
margin: 16px 0 8px;
font-weight: 600;
line-height: 1.4;
}
.markdown-body h1 {
font-size: 20px;
border-bottom: 1px solid #ebeef5;
padding-bottom: 8px;
}
.markdown-body h2 {
font-size: 18px;
}
.markdown-body h3 {
font-size: 16px;
}
.markdown-body ul {
margin: 8px 0;
padding-left: 24px;
}
.markdown-body li {
margin: 4px 0;
}
.markdown-body code {
background-color: #f5f7fa;
padding: 2px 6px;
border-radius: 4px;
font-family: 'Courier New', Courier, monospace;
font-size: 13px;
}
.markdown-body pre {
background-color: #f5f7fa;
padding: 12px;
border-radius: 6px;
overflow-x: auto;
margin: 12px 0;
}
.markdown-body pre code {
background-color: transparent;
padding: 0;
}
.empty-content {
color: #909399;
text-align: center;
}
移动端(Vant)
.markdown-body {
font-size: 14px;
line-height: 1.8;
color: #333;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3 {
margin: 16px 0 8px;
font-weight: 600;
line-height: 1.4;
}
.markdown-body h1 {
font-size: 18px;
border-bottom: 1px solid #ebedf0;
padding-bottom: 8px;
}
.markdown-body h2 {
font-size: 16px;
}
.markdown-body h3 {
font-size: 15px;
}
.markdown-body ul {
margin: 8px 0;
padding-left: 20px;
}
.markdown-body li {
margin: 4px 0;
}
.markdown-body code {
background-color: #f5f7fa;
padding: 2px 6px;
border-radius: 4px;
font-family: 'Courier New', Courier, monospace;
font-size: 13px;
}
.markdown-body pre {
background-color: #f5f7fa;
padding: 12px;
border-radius: 6px;
overflow-x: auto;
margin: 12px 0;
}
.markdown-body pre code {
background-color: transparent;
padding: 0;
}
.empty-content {
color: #969799;
text-align: center;
}
支持的Markdown语法
| 语法 | Markdown | 渲染结果 |
|---|---|---|
| 一级标题 | # 标题 |
<h1>标题</h1> |
| 二级标题 | ## 标题 |
<h2>标题</h2> |
| 三级标题 | ### 标题 |
<h3>标题</h3> |
| 粗体 | **文本** |
<strong>文本</strong> |
| 斜体 | *文本* |
<em>文本</em> |
| 行内代码 | `代码` |
<code>代码</code> |
| 代码块 | ```代码块``` |
<pre><code>代码块</code></pre> |
| 无序列表 | - 列表项 |
<ul><li>列表项</li></ul> |
| 段落换行 | 空行分隔 | <p> 标签 |
| 普通换行 | 单个换行 | <br> |
安全说明
重要:渲染前必须转义HTML特殊字符(&, <, >),防止XSS攻击。
// 必须首先执行
content = content
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
使用示例
日志详情弹窗
<template>
<el-dialog v-model="visible" width="700px">
<template #header>
<div class="log-detail-header">
<div class="header-left">
<span class="log-date">{{ logDate }}</span>
<span class="log-title">{{ title }}</span>
</div>
<span class="log-user">{{ userName }}</span>
</div>
</template>
<div class="log-detail-content">
<div class="markdown-body" v-html="renderedContent"></div>
</div>
</el-dialog>
</template>
注意事项
- 性能考虑:对于大量内容的渲染,考虑使用
v-memo或虚拟滚动 - 代码高亮:如需语法高亮,可额外集成highlight.js或prism.js
- 扩展语法:当前实现为基础语法,如需表格、引用等可按需扩展