Использование Vue в Markdown
В VitePress каждый файл Markdown компилируется в HTML, а затем обрабатывается как Vue однофайловый компонент (Single-File Component, SFC). Это означает, что вы можете использовать любые возможности Vue внутри Markdown, включая динамическое шаблонирование, использование компонентов Vue или произвольную логику компонентов Vue на странице, добавляя тег <script>
.
Стоит отметить, что 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>
Вывод
123
<script>
и <style>
Теги <script>
и <style>
на корневом уровне в файлах Markdown работают так же, как и в Vue SFC, включая <script setup>
, <style module>
и т.д. Основное отличие здесь в том, что нет тега <template>
: все остальное содержимое на корневом уровне - это Markdown. Также обратите внимание, что все теги должны быть размещены после frontmatter:
---
hello: world
---
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
## Содержимое Markdown
Счетчик: {{ count }}
<button :class="$style.button" @click="count++">Увеличить</button>
<style module>
.button {
color: red;
font-weight: bold;
}
</style>
Избегайте <style scoped>
в Markdown
При использовании в Markdown <style scoped>
требуется добавление специальных атрибутов ко всем элементам на текущей странице, что значительно увеличит размер страницы. <style module>
предпочтительнее, когда необходим стиль с локальной областью видимости на странице.
У вас также есть доступ к API времени выполнения VitePress, таким как помощник useData
, который предоставляет доступ к метаданным текущей страницы:
Ввод
<script setup>
import { useData } from 'vitepress'
const { page } = useData()
</script>
<pre>{{ page }}</pre>
Вывод
{
"path": "/using-vue.html",
"title": "Использование Vue в Markdown",
"frontmatter": {},
...
}
Использование компонентов
Вы можете напрямую импортировать и использовать компоненты Vue в файлах Markdown.
Импорт в Markdown
Если компонент используется только на нескольких страницах, рекомендуется явно импортировать их там, где они используются. Это позволяет им быть должным образом разделенными на коды и загружаться только тогда, когда соответствующие страницы показаны:
<script setup>
import CustomComponent from '../components/CustomComponent.vue'
</script>
# Документация
Это .md файл, использующий пользовательский компонент
<CustomComponent />
## Больше документации
...
Глобальная регистрация компонентов
Если компонент будет использоваться на большинстве страниц, его можно зарегистрировать глобально, настраивая экземпляр приложения Vue. Смотрите соответствующий раздел в Расширение стандартной темы для примера.
ВАЖНО
Убедитесь, что имя пользовательского компонента содержит дефис или написано в PascalCase. В противном случае он будет рассматриваться как встроенный элемент и обернут в тег <p>
, что приведет к несоответствию гидратации, поскольку в <p>
нельзя помещать блочные элементы.
Использование компонентов в заголовках ⚡
Вы можете использовать компоненты Vue в заголовках, но обратите внимание на разницу между следующими синтаксисами:
Markdown | Вывод HTML | Разобранный заголовок |
---|---|---|
| <h1>текст <Tag/></h1> | текст |
| <h1>текст <code><Tag/></code></h1> | текст <Tag/> |
HTML, обернутый в <code>
, будет отображаться как есть; только HTML, который не обернут, будет разобран Vue.
Подсказка
Вывод HTML достигается с помощью Markdown-it, в то время как разобранные заголовки обрабатываются VitePress (и используются как для боковой панели, так и для заголовка документа).
Экранирование
Вы можете экранировать интерполяции Vue, обернув их в <span>
или другие элементы с директивой v-pre
:
Ввод
Это <span v-pre>{{ будет отображаться как есть }}</span>
Вывод
Это {{ будет отображаться как есть }}
Кроме того, вы можете обернуть весь абзац в пользовательский контейнер v-pre
:
::: v-pre
{{ Это будет отображаться как есть }}
:::
Вывод
{{ Это будет отображаться как есть }}
Разблокировка в блоках кода
По умолчанию все ограниченные блоки кода автоматически оборачиваются v-pre
, поэтому синтаксис Vue не будет обрабатываться внутри. Чтобы включить интерполяцию в стиле Vue внутри ограждений, вы можете добавить к языку суффик
с -vue
, например, js-vue
:
Ввод
```js-vue
Привет {{ 1 + 1 }}
```
Вывод
Привет 2
Обратите внимание, что это может помешать правильной подсветке синтаксиса некоторых токенов.
Использование CSS-препроцессоров
VitePress имеет встроенную поддержку для CSS-препроцессоров: .scss
, .sass
, .less
, .styl
и .stylus
файлов. Нет необходимости устанавливать специфические для Vite плагины для них, но сам препроцессор должен быть установлен:
# .scss и .sass
npm install -D sass
# .less
npm install -D less
# .styl и .stylus
npm install -D stylus
Затем вы можете использовать следующее в файлах Markdown и компонентах темы:
<style lang="sass">
.title
font-size: 20px
</style>
Использование Teleport
На данный момент VitePress поддерживает SSG для teleport только в body. Для других целей вы можете обернуть их во встроенный компонент <ClientOnly>
или внедрить разметку teleport в правильное место в вашем итоговом HTML-коде страницы через хук postRender
.
Реализация
<script setup lang="ts">
import { ref } from 'vue'
const showModal = ref(false)
</script>
<template>
<button class="modal-button" @click="showModal = true">Показать модальное окно</button>
<Teleport to="body">
<Transition name="modal">
<div v-show="showModal" class="modal-mask">
<div class="modal-container">
<p>Привет из модального окна!</p>
<div class="model-footer">
<button class="modal-button" @click="showModal = false">
Закрыть
</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>