跳到內容

在 Markdown 中使用 Vue

在 VitePress 中,每個 Markdown 檔案會編譯成 HTML,然後當作 Vue 單一檔案元件 處理。這表示您可以在 Markdown 中使用任何 Vue 功能,包括動態範本、使用 Vue 元件,或透過新增 <script> 標籤新增任意頁面內 Vue 元件邏輯。

值得注意的是,VitePress 採用 Vue 的編譯器自動偵測並最佳化 Markdown 內容中純靜態的部分。靜態內容會最佳化成單一佔位符節點,並從頁面的 JavaScript 負載中移除,以進行首次造訪。它們也會在用戶端水化期間略過。簡而言之,您只會為任何特定頁面上的動態部分付費。

SSR 相容性

所有 Vue 使用都必須與 SSR 相容。請參閱 SSR 相容性 以取得詳細資訊和常見的解決方法。

範本

內插

每個 Markdown 檔案會先編譯成 HTML,然後傳遞給 Vite 處理程序管道,當作 Vue 元件。這表示您可以在文字中使用 Vue 風格的內插

輸入

md
{{ 1 + 1 }}

輸出

2

指令

指令也適用(請注意,根據設計,原始 HTML 在 Markdown 中也同樣有效)

輸入

html
<span v-for="i in 3">{{ i }}</span>

輸出

1 2 3 

<script><style>

Markdown 檔案中的根層級 <script><style> 標籤就像在 Vue SFC 中一樣運作,包括 <script setup><style module> 等。這裡的主要差別在於沒有 <template> 標籤:所有其他根層級內容都是 Markdown。另外請注意,所有標籤都應該放在frontmatter 之後

html
---
hello: world
---

<script setup>
import { ref } from 'vue'

const count = ref(0)
</script>

## Markdown Content

The count is: {{ count }}

<button :class="$style.button" @click="count++">Increment</button>

<style module>
.button {
  color: red;
  font-weight: bold;
}
</style>

在 Markdown 中避免使用 <style scoped>

在 Markdown 中使用時,<style scoped> 需要為當前頁面上的每個元素新增特殊屬性,這將大幅增加頁面大小。當頁面需要局部範圍的樣式時,建議使用 <style module>

您還可以存取 VitePress 的執行時期 API,例如 useData 輔助函式,它提供存取當前頁面元資料的功能

輸入

html
<script setup>
import { useData } from 'vitepress'

const { page } = useData()
</script>

<pre>{{ page }}</pre>

輸出

json
{
  "path": "/using-vue.html",
  "title": "Using Vue in Markdown",
  "frontmatter": {},
  ...
}

使用元件

您可以在 Markdown 檔案中直接匯入和使用 Vue 元件。

在 Markdown 中匯入

如果元件只在少數頁面中使用,建議在使用它們的地方明確匯入。這允許它們適當地進行程式碼分割,並且只在顯示相關頁面時載入

md
<script setup>
import CustomComponent from '../components/CustomComponent.vue'
</script>

# Docs

This is a .md using a custom component

<CustomComponent />

## More docs

...

全域註冊元件

如果元件將在大部分頁面上使用,它們可以透過自訂 Vue 應用程式實例來進行全域註冊。請參閱 擴充預設佈景主題 中相關區段以取得範例。

重要

請確保自訂元件的名稱包含連字號或使用 PascalCase。否則,它將被視為內嵌元素並封裝在 <p> 標籤內,這將導致水化不匹配,因為 <p> 不允許在其中放置區塊元素。

在標題中使用元件

您可以在標題中使用 Vue 元件,但請注意以下語法的差異

Markdown輸出 HTML已剖析標題
 # text <Tag/> 
<h1>文字 <Tag/></h1>文字
 # text `<Tag/>` 
<h1>文字 <code>&lt;Tag/&gt;</code></h1>文字 <Tag/>

<code> 包起來的 HTML 將會原樣顯示;只有包起來的 HTML 才會被 Vue 剖析。

提示

輸出 HTML 是由 Markdown-it 完成的,而已剖析的標題則是由 VitePress 處理(並同時用於側邊欄和文件標題)。

跳脫

您可以透過將 Vue 插值包在 <span> 或其他具有 v-pre 指令的元素中來跳脫它們

輸入

md
This <span v-pre>{{ will be displayed as-is }}</span>

輸出

{{ 將會原樣顯示 }}

或者,您可以將整個段落包在 v-pre 自訂容器中

md
::: v-pre
{{ This will be displayed as-is }}
:::

輸出

{{ 這將會原樣顯示 }}

在程式碼區塊中取消跳脫

預設情況下,所有圍欄式程式碼區塊都會自動以 v-pre 包起來,因此不會處理區塊內的任何 Vue 語法。若要在圍欄內啟用 Vue 風格的插值,您可以將語言加上 -vue 字尾,例如 js-vue

輸入

md
```js-vue
Hello {{ 1 + 1 }}
```

輸出

js
Hello 2

請注意,這可能會導致某些代碼無法正確地以語法高亮顯示。

使用 CSS 預處理器

VitePress 內建支援 CSS 預處理器:.scss.sass.less.styl.stylus 檔案。不需要為它們安裝 Vite 特定的外掛程式,但必須安裝對應的預處理器本身

# .scss and .sass
npm install -D sass

# .less
npm install -D less

# .styl and .stylus
npm install -D stylus

然後您可以在 Markdown 和佈景主題元件中使用以下內容

vue
<style lang="sass">
.title
  font-size: 20px
</style>

使用傳送

Vitepress 目前僅支援傳送至主體的 SSG。對於其他目標,您可以將它們包在內建的 <ClientOnly> 元件中,或透過 postRender 鉤子 將傳送標記注入至最終頁面 HTML 中正確的位置。

Details
vue
<script setup lang="ts">
import { ref } from 'vue'
const showModal = ref(false)
</script>

<template>
  <button class="modal-button" @click="showModal = true">Show Modal</button>

  <Teleport to="body">
    <Transition name="modal">
      <div v-show="showModal" class="modal-mask">
        <div class="modal-container">
          <p>Hello from the modal!</p>
          <div class="model-footer">
            <button class="modal-button" @click="showModal = false">
              Close
            </button>
          </div>
        </div>
      </div>
    </Transition>
  </Teleport>
</template>

<style scoped>
.modal-mask {
  position: fixed;
  z-index: 200;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.3s ease;
}

.modal-container {
  width: 300px;
  margin: auto;
  padding: 20px 30px;
  background-color: var(--vp-c-bg);
  border-radius: 2px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
  transition: all 0.3s ease;
}

.model-footer {
  margin-top: 8px;
  text-align: right;
}

.modal-button {
  padding: 4px 8px;
  border-radius: 4px;
  border-color: var(--vp-button-alt-border);
  color: var(--vp-button-alt-text);
  background-color: var(--vp-button-alt-bg);
}

.modal-button:hover {
  border-color: var(--vp-button-alt-hover-border);
  color: var(--vp-button-alt-hover-text);
  background-color: var(--vp-button-alt-hover-bg);
}

.modal-enter-from,
.modal-leave-to {
  opacity: 0;
}

.modal-enter-from .modal-container,
.modal-leave-to .modal-container {
  transform: scale(1.1);
}
</style>
md
<ClientOnly>
  <Teleport to="#modal">
    <div>
      // ...
    </div>
  </Teleport>
</ClientOnly>

在 MIT 授權下發布。