跳轉到內容

在 Markdown 中使用 Vue ​

在 VitePress 中,每个 Markdown 文件都被编译成 HTML,而且将其作为 Vue 单文件组件處理。这意味着可以在 Markdown 中使用任何 Vue 功能,包括动態模板、使用 Vue 组件或通過新增 <script> 标签为頁面的 Vue 组件新增逻辑。

值得注意的是,VitePress 利用 Vue 的编译器自动检測和优化 Markdown 内容的纯靜態部分。靜態内容被优化为单个占位符节点,并从頁面的 JavaScript 负载中删除以供初始访问。在客戶端激活期间也會跳過它们。简而言之,只需注意任何给定頁面上的动態部分。

SSR 相容性

所有的 Vue 用法都需要相容 SSR。参见 SSR 相容性获得更多信息和常见的解决方案。

模板化 ​

插值语法 ​

每个 Markdown 文件首先被编译成 HTML,然後作为 Vue 组件传递给 Vite 流程管道。这意味着可以在文本中使用 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>text <Tag/></h1>text
 # text `<Tag/>` 
<h1>text <code>&lt;Tag/&gt;</code></h1>text <Tag/>

被 <code> 包裹的 HTML 将按原样显示,只有未包裹的 HTML 才會被 Vue 解析。

TIP

输出 HTML 由 Markdown-it 完成,而解析的标题由 VitePress 處理 (并用于侧边栏和文件标题)。

转义 ​

可以通過使用 v-pre 指令将它们包裹在 <span> 或其他元素中来转义 Vue 插值:

输入

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

输出

This {{ will be displayed as-is }}

也可以将整个段落包装在 v-pre 自訂容器中:

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

输出

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

使用 teleport 传递组件内容 ​

VitePress 目前只有使用 teleport 传送到 body 的 SSG 支援。对于其他地方,可以将它们包裹在内置的 <ClientOnly> 组件中,或者通過 postRender 钩子将 teleport 标签注入到最终頁面 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 授權發布