Skip to content

MermaidBlockNode (Component)

MermaidBlockNode 提供一个易于使用且可扩展的 Mermaid 渲染器,适用于需要在文档中内嵌交互式 Mermaid 图的场景。组件支持渐进式渲染、源码/预览切换、复制源码、导出 SVG,以及伪全屏查看(带缩放与拖拽)。

Props(关键)

  • node: any — Mermaid 代码节点(必须)
  • isDark?: boolean — 暗色模式开关
  • loading?: boolean — 初始加载占位
  • maxHeight?: string | null — 最大高度
  • estimatedPreviewHeightPx?: number — Mermaid 完成渲染前预留的首屏 preview 高度;通过 MarkdownRender 渲染 Mermaid 围栏时会自动填入
  • isStrict?: boolean — 默认 true;开启 securityLevel: 'strict' + DOMPurify,并禁用 HTML labels。只有可信图表确实需要 Mermaid HTML labels 时才设为 false
  • Header/按钮控制(全部可选,默认 true):
    • showHeader / showModeToggle / showCopyButton / showExportButton / showFullscreenButton / showCollapseButton / showZoomControls / showTooltips
  • enableWheelZoom?: boolean — 开启 Ctrl/Cmd + 滚轮缩放(默认 false
  • 超时(毫秒):workerTimeoutMs / parseTimeoutMs / renderTimeoutMs / fullRenderTimeoutMs(默认 1400/1800/2500/4000
  • 流式调优:renderDebounceMs / contentStableDelayMs / previewPollDelayMs / previewPollMaxDelayMs / previewPollMaxAttempts

Slots

  • header-left — 替换左侧(默认是 Mermaid 图标 + 标签)
  • header-center — 替换中间区域(默认 preview/source 切换)
  • header-right — 替换右侧操作按钮(完整接管默认按钮)

Emits

组件发出的事件都使用统一的 MermaidBlockEvent 对象,支持 preventDefault() 来阻止组件默认行为:

  • copy — 点击复制按钮,处理签名:(ev: MermaidBlockEvent<{ type: 'copy'; text: string }>)(调用 ev.preventDefault() 可阻止组件默认的复制到剪贴板与 “Copied” 状态)
  • export — 导出按钮点击,处理签名:(ev: MermaidBlockEvent<{ type: 'export' }>)
  • openModal — 请求打开 pseudo-fullscreen,处理签名:(ev: MermaidBlockEvent<{ type: 'open-modal' }>)(组件内部 emit 名称为 openModal
  • toggleMode — 切换 source | preview,处理签名:(target: 'source' | 'preview', ev: MermaidBlockEvent<{ type: 'toggle-mode'; target: 'source' | 'preview' }>)(组件内部 emit 名称为 toggleMode

拦截示例

完全替换组件默认导出行为:

vue
<script setup lang="ts">
import type { MermaidBlockEvent } from 'markstream-vue'
import { MermaidBlockNode } from 'markstream-vue'

function onExport(ev: any /* MermaidBlockEvent */) {
  ev.preventDefault()
  // 组件在事件对象中暴露了 svgElement,直接使用它更方便
  const svgEl = ev.svgElement as SVGElement | null
  if (!svgEl) {
    console.warn('No svg element available')
    return
  }
  const svgString = new XMLSerializer().serializeToString(svgEl)
  uploadSvg(svgString)
}
</script>

<template>
  <MermaidBlockNode :node="node" @export="onExport" />
</template>

注意:export / openModal 事件的事件对象现已同时包含 svgElement(DOM 节点)和 svgString(已序列化的 SVG 字符串),任选其一使用更方便。

Slot 示例:完全接管右侧操作按钮

vue
<MermaidBlockNode :node="node" :showExportButton="false">
  <template #header-right>
    <button @click="downloadSvg">Download</button>
    <button @click="openCustomModal">Open custom modal</button>
  </template>
</MermaidBlockNode>

推荐用法

  • 如果你要实现自定义导出/上传,最佳做法是:在 export 监听器中 preventDefault(),并在监听回调中直接从组件渲染的 DOM 中读取 svg
  • 如果你想要完全替换头部的 UI,使用 header-* 插槽并把相应 show* props 设为 false 来隐藏默认按钮。
  • Mermaid 严格模式默认开启,因此用户/LLM 图表会经过 SVG 清理并禁用 HTML labels。只有可信图表需要宽松 Mermaid 渲染时,才设置 :is-strict="false"

对可信图表恢复 loose 模式

如果某个可信 Mermaid 图依赖 HTML labels,或者依赖旧的 loose 模式渲染结果,可以按组件粒度显式关闭 strict,而不是把更安全的默认值整体改回去:

vue
<script setup lang="ts">
import { MermaidBlockNode } from 'markstream-vue'

const node = {
  type: 'code_block',
  language: 'mermaid',
  code: 'flowchart TD\n  A["<b>可信</b><br/>label"] --> B',
  raw: 'flowchart TD\n  A["<b>可信</b><br/>label"] --> B',
}
</script>

<template>
  <MermaidBlockNode :node="node" :is-strict="false" />
</template>

只有 Mermaid 源内容可信时才建议这样做;用户内容或 LLM 输出仍建议保留默认 strict。

参考

Playground 示例:仓库包含一个可运行的 playground 页面演示如何拦截 export 并上传 ev.svgString —— 路由: mermaid-export-demo (文件:playground/src/pages/mermaid-export-demo.vue)。