自訂渲染

只有在您想擁有整個圖表體驗時才使用自訂渲染器(custom renderer)。
若只需要外圍版面、共用載入介面或錯誤呈現,請改為包裝 <Mermaid>,保留內建渲染器。

了解渲染器選擇

components.renderer 設為 ~/components 中元件的名稱:

export default defineNuxtConfig({
  contentMermaid: {
    components: {
      renderer: 'CustomMermaid',
      spinner: 'MermaidSpinner',
    },
  },
})

設定的名稱是自訂渲染器候選項(Custom Renderer Candidate)。
用戶端上,套件會遞迴搜尋 ~/components,找出相符檔名;比對會忽略大小寫、空格、底線、連字號、路徑區段與選用的 .vue 副檔名。

解析結果渲染擁有者(Rendering Owner)
沒有渲染器名稱內建渲染器(Built-in Renderer)。
候選項載入中尚未有渲染器;預設原始碼備援內容保持可見。
候選項解析成功自訂渲染器,且獨占所有權。
找不到候選項或載入失敗顯示主控台診斷訊息後使用內建渲染器。

對每個已解析的候選項,這是單向的所有權選擇。
之後自訂渲染器若掛載或渲染失敗,不會再觸發第二次內建備援。
它的載入與錯誤介面、主題決策、Mermaid 呼叫、工具列、全螢幕、展開與可存取性行為都必須由您實作。

實作完整的自訂渲染器

解析成功的自訂渲染器只會收到以下擴充輸入(extension inputs):

  • code:呼叫端傳入時,已解碼的 Mermaid 原始碼。
  • spinner:設定的載入指示元件,或套件的載入指示備援元件。
  • 預設插槽(slot):由 <Mermaid> 提供的原始碼備援內容。

它不會收到內建的 pageConfig、直接 config、工具列選項、載入插槽、錯誤插槽、自動主題解析或 components.error。請明確擁有這些關切點:

<!-- components/CustomMermaid.vue -->
<script setup lang="ts">
import { onMounted, ref, shallowRef, useId } from 'vue'
import type { Component } from 'vue'

const props = defineProps<{
  code?: string
  spinner: Component | string
}>()

const loading = ref(true)
const error = shallowRef<unknown>()
const svg = ref('')
const renderId = `custom-mermaid-${useId().replaceAll(':', '')}`

onMounted(async () => {
  try {
    const mermaid = await useNuxtApp().$mermaid()
    svg.value = (await mermaid.render(renderId, props.code ?? '')).svg
  }
  catch (cause) {
    error.value = cause
  }
  finally {
    loading.value = false
  }
})
</script>

<template>
  <section class="custom-mermaid">
    <component :is="props.spinner" v-if="loading" />
    <p v-else-if="error" role="alert">
      Diagram failed: {{ error instanceof Error ? error.message : String(error) }}
    </p>
    <div v-else v-html="svg" />
  </section>
</template>

此範例刻意自行擁有失敗呈現。若自訂渲染器需要主題變更或 Mermaid 設定,請提供並回應自己的應用程式層級狀態,而不要期待內建渲染器的屬性(props)。

改為包裝內建渲染器

不要把這個外層元件(wrapper)設為 components.renderer
它是一般的應用程式元件:在加入呈現外觀時,仍保留內建的設定、互動、載入與錯誤行為:

<!-- components/DiagramCard.vue -->
<script setup lang="ts">
const props = defineProps<{
  title: string
  source: string
}>()

const encodedSource = computed(() => encodeURIComponent(props.source))
</script>

<template>
  <section class="diagram-card">
    <h2>{{ title }}</h2>
    <Mermaid :code="encodedSource">
      <template #loading>
        <p aria-live="polite">正在渲染圖表…</p>
      </template>
      <template #error="{ error, source }">
        <p role="alert">
          Render failed: {{ error instanceof Error ? error.message : String(error) }}
        </p>
        <details>
          <summary>顯示 Mermaid 原始碼</summary>
          <pre><code>{{ source }}</code></pre>
        </details>
      </template>
    </Mermaid>
  </section>
</template>

若 Nuxt 設定未自動匯入 Vue 工具函式,請加入 import { computed } from 'vue'
內建渲染器接受預設插槽作為原始碼備援內容、#loading 作為初始載入狀態,以及 #error="{ error, source }" 作為 Mermaid 渲染失敗。或者可由 components.error 提供全域內建錯誤元件,並接收 errorsource;自訂渲染器不會使用它。

避免遞迴渲染器選擇

絕對不要在設定為 components.renderer 的元件中渲染 <Mermaid>。巢狀元件會重複選擇候選項,可能無限遞迴。
請改為呼叫 useNuxtApp().$mermaid()、另一個渲染器,或獨立的較低層實作。只有未被設定為自訂渲染器的外層元件才是安全的。