在 Markdown 中使用 Vue
在 VitePress 中,每个 Markdown 文件都会被编译成 HTML,然后作为 Vue 单文件组件 处理。这意味着您可以在 Markdown 中使用任何 Vue 功能,包括动态模板、使用 Vue 组件,或者通过添加 <script>
标签来实现任意页面内 Vue 组件逻辑。
值得注意的是,VitePress 利用 Vue 的编译器自动检测和优化 Markdown 内容中纯粹的静态部分。静态内容被优化为单个占位符节点,并从页面的 JavaScript 负载中删除,以便进行初始访问。它们在客户端水合过程中也会被跳过。简而言之,您只需为任何给定页面上的动态部分付费。
SSR 兼容性
所有 Vue 使用都需要与 SSR 兼容。有关详细信息和常见解决方法,请参阅 SSR 兼容性。
模板
插值
每个 Markdown 文件首先被编译成 HTML,然后作为 Vue 组件传递到 Vite 进程管道。这意味着您可以在文本中使用 Vue 风格的插值
输入
{{ 1 + 1 }}
输出
2
指令
指令也适用(请注意,根据设计,原始 HTML 在 Markdown 中也是有效的)
输入
<span v-for="i in 3">{{ i }}</span>
输出
1 2 3
<script>
和 <style>
Markdown 文件中的根级 <script>
和 <style>
标签的工作方式与 Vue SFC 中一样,包括 <script setup>
、<style module>
等。这里的主要区别在于没有 <template>
标签:所有其他根级内容都是 Markdown。还要注意,所有标签都应该放在前置信息之后
---
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
帮助程序,它提供了对当前页面元数据的访问权限
输入
<script setup>
import { useData } from 'vitepress'
const { page } = useData()
</script>
<pre>{{ page }}</pre>
输出
{
"path": "/using-vue.html",
"title": "Using Vue in Markdown",
"frontmatter": {},
...
}
使用组件
您可以在 Markdown 文件中直接导入和使用 Vue 组件。
在 Markdown 中导入
如果一个组件只被少数页面使用,建议在使用的地方显式导入它们。这允许它们被正确地代码分割,并且只有在显示相关页面时才会加载
<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 | 解析后的标题 |
---|---|---|
| <h1>text <Tag/></h1> | text |
| <h1>text <code><Tag/></code></h1> | text <Tag/> |
被 <code>
包裹的 HTML 将按原样显示;只有没有被包裹的 HTML 将被 Vue 解析。
提示
输出 HTML 是由 Markdown-it 完成的,而解析后的标题由 VitePress 处理(并用于侧边栏和文档标题)。
转义
您可以通过将 Vue 插值包装在 <span>
或其他带有 v-pre
指令的元素中来转义它们
输入
This <span v-pre>{{ will be displayed as-is }}</span>
输出
这 {{ 将按原样显示 }}
或者,您可以将整个段落包装在 v-pre
自定义容器中
::: v-pre
{{ This will be displayed as-is }}
:::
输出
{{ 这将按原样显示 }}
在代码块中取消转义
默认情况下,所有围栏代码块都会自动用 v-pre
包装,因此围栏内部不会处理任何 Vue 语法。要启用围栏内部的 Vue 风格插值,可以在语言后追加 -vue
后缀,例如 js-vue
输入
```js-vue
Hello {{ 1 + 1 }}
```
输出
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 和主题组件中使用以下内容
<style lang="sass">
.title
font-size: 20px
</style>
使用传送门
Vitepress 目前仅支持将传送门到 body 的 SSG 支持。对于其他目标,您可以将它们包装在内置的 <ClientOnly>
组件中,或者通过 postRender
钩子 将传送门标记注入到最终页面 HTML 的正确位置。
详细信息
<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>
<ClientOnly>
<Teleport to="#modal">
<div>
// ...
</div>
</Teleport>
</ClientOnly>