worklog/.qoder/skills/markdown-render.md
zhangjf 90a5c032c2 docs: 添加开发技能文档(skills)
- markdown-render.md: Markdown渲染实现方案
- dashboard-calendar.md: 管理后台首页日历功能实现
2026-02-25 01:28:34 +08:00

5.3 KiB
Raw Blame History

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, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
  
  // 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, '&amp;')
  .replace(/</g, '&lt;')
  .replace(/>/g, '&gt;')

使用示例

日志详情弹窗

<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>

注意事项

  1. 性能考虑:对于大量内容的渲染,考虑使用v-memo或虚拟滚动
  2. 代码高亮如需语法高亮可额外集成highlight.js或prism.js
  3. 扩展语法:当前实现为基础语法,如需表格、引用等可按需扩展