Skip to content

Markdown

The Markdown component's core is built on the unified and remark ecosystem. It parses Markdown text into an AST (Abstract Syntax Tree) and leverages Vue's rendering mechanism to convert it into DOM nodes. This architecture design gives the component extremely high flexibility, supporting Slots and custom component rendering to meet complex business requirements.

Features:

  • Core Engine: Based on unified and remark, providing precise parsing and a rich ecosystem.
  • Vue Rendering: Uses Vue to render AST, supporting seamless embedding of Vue components and slots.
  • Built-in Support: Default support for math formulas (KaTeX), code highlighting, Mermaid flowcharts/sequence diagrams, etc.
  • Extensibility: Supports custom extensions, easily integrating third-party chart libraries like ECharts.
  • Component Decomposition: Markdown breaks down basic Code Highlighting and Mermaid into two separate components.

Basic Usage

Basic Mathematical Formulas

Slot - Custom Toolbar

Slot - Custom Code Block Using ECharts

Custom ECharts File Example ./echarts-test.vue
vue
<template>
  <div
    ref="echartsDom"
    style="width: 100%; height: 400px; margin: 16px 0"
  ></div>
</template>

<script setup lang="ts">
import { computed, onMounted, onUnmounted, useTemplateRef, watch } from 'vue'
import JSON5 from 'json5'
import * as echarts from 'echarts'

const props = defineProps({
  content: {
    type: String,
    required: true,
  },
  theme: {
    type: String,
    default: 'light',
  },
})
let myChart: echarts.ECharts | null = null
const echartsDom = useTemplateRef('echartsDom')

const options = computed(() => {
  const regex = /option\s*=\s*({[\s\S]*});?$/
  const match = props.content.trim().match(regex)
  if (match) {
    try {
      return JSON5.parse(match[1])
    } catch (e) {
      return null
    }
  }
})

const renderChart = () => {
  if (!echartsDom.value) return
  if (!myChart) {
    myChart = echarts.init(echartsDom.value, props.theme)
  }
  if (options.value) {
    myChart.setTheme(props.theme === 'dark' ? 'dark' : 'default')
    myChart.setOption(options.value)
  }
}

const handleResize = () => {
  myChart?.resize()
}

watch([options, () => props.theme], () => {
  renderChart()
})
onMounted(() => {
  renderChart()
  window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
  if (myChart) {
    myChart.dispose()
    myChart = null
  }
  window.removeEventListener('resize', handleResize)
})
</script>

<style scoped></style>

Typewriter Output

Props

PropertyDescriptionTypeDefault
themeTheme mode'dark' | 'light''light'
contentMarkdown contentstring''
remarkPluginsCustom remark pluginsMiddlewarePluginItem[][]
codeHighlightPropsProps passed to CodeHighlight componentCodeHighlightPropsType{}
codeMermaidPropsProps passed to CodeMermaid componentCodeMermaidPropsType{}

Slots

Slot NameDescriptionParameters
mermaidCustom Mermaid code block render{ content, language, theme, ...codeMermaidProps }
code-mermaid-toolbarCustom Mermaid toolbarSee CodeMermaid component docs
code-mermaid-fullscreen-toolbarCustom Mermaid fullscreen toolbarSee CodeMermaid component docs
codeCustom code block render{ content, language, theme, ...codeHighlightProps }
code-highlight-headerCustom code block headerSee CodeHighlight component docs