Usando Vue em Markdown
Em VitePress, cada arquivo Markdown é compilado para HTML e então processado como um Componente de Arquivo Único Vue. Isso significa que você pode usar qualquer funcionalidade Vue dentro do Markdown, incluindo a interpolação dinâmica, usar componentes Vue ou lógica arbitrária de componentes Vue dentro da página adicionando uma tag <script>
.
Vale ressaltar que VitePress aproveita o compilador Vue para detectar e otimizar automaticamente as partes puramente estáticas do conteúdo Markdown. Os conteúdos estáticos são otimizados em nós de espaço reservado únicos e eliminados da carga JavaScript da página para visitas iniciais. Eles também são ignorados durante a hidratação no lado do cliente. Em resumo, você só paga pelas partes dinâmicas em qualquer página específica.
Compatibilidade SSR
Todo uso do Vue precisa ser compatível com SSR. Consulte Compatibilidade SSR para detalhes e soluções comuns.
Criação de Templates
Interpolação
Cada arquivo Markdown é primeiro compilado para HTML e depois passado como um componente Vue para a canalização de processos Vite. Isso significa que você pode usar interpolação no estilo Vue no texto:
Entrada
{{ 1 + 1 }}
Saída
2
Diretivas
Diretivas também funcionam (observe que, por definiçào, HTML cru também é válido em Markdown):
Entrada
<span v-for="i in 3">{{ i }}</span>
Saída
1 2 3
<script>
e <style>
As tags <script>
e <style>
em nível raiz nos arquivos Markdown funcionam igualmente como nos Componentes de Arquivo Único Vue, incluindo <script setup>
, <style module>
, e etc. A principal diferença aqui é que não há uma tag <template>
: todo outro conteúdo em nível raiz é Markdown. Além disso, observe que todas as tags devem ser colocadas após o frontmatter:
---
hello: world
---
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
## Conteúdo Markdown
A contagem é: {{ count }}
<button :class="$style.button" @click="count++">Incrementar</button>
<style module>
.button {
color: red;
font-weight: bold;
}
</style>
Evite <style scoped>
no Markdown
Quando usado no Markdown, <style scoped>
exige a adição de atributos especiais a cada elemento na página atual, o que aumentará significativamente o tamanho da página. <style module>
é preferido quando é necessária uma estilização localizada em uma página.
Você também tem acesso às APIs de tempo de execução VitePress, como o auxiliar useData
, que fornece acesso aos metadados da página atual:
Entrada
<script setup>
import { useData } from 'vitepress'
const { page } = useData()
</script>
<pre>{{ page }}</pre>
Saída
{
"path": "/usando-vue.html",
"title": "Usando Vue em Markdown",
"frontmatter": {},
...
}
Usando Componentes
Você pode importar e usar componentes Vue diretamente nos arquivos Markdown.
Importando no Markdown
Se um componente é usado apenas por algumas páginas, é recomendável importá-los explicitamente onde são usados. Isso permite que eles sejam divididos adequadamente e carregados apenas quando as páginas relevantes são mostradas:
<script setup>
import CustomComponent from '../components/CustomComponent.vue'
</script>
# Documentação
Este é um arquivo .md usando um componente personalizado
<CustomComponent />
## Mais documentação
...
Registrando Componentes Globalmente
Se um componente for usado na maioria das páginas, eles podem ser registrados globalmente personalizando a instância do aplicativo Vue. Consulte a seção relevante em Estendendo o Tema Padrão para um exemplo.
IMPORTANT
Certifique-se de que o nome de um componente personalizado contenha um hífen ou esteja em PascalCase. Caso contrário, ele será tratado como um elemento alinhado e envolvido dentro de uma tag <p>
, o que levará a uma incompatibilidade de hidratação pois <p>
não permite que elementos de bloco sejam colocados dentro dele.
Usando Componentes Em Cabeçalhos <ComponenteNoCabeçalho />
Você pode usar componentes Vue nos cabeçalhos, mas observe a diferença entre as seguintes sintaxes:
Markdown | HTML de Saída | Cabeçalho Processado |
---|---|---|
| <h1>texto <Tag/></h1> | texto |
| <h1>texto <code><Tag/></code></h1> | texto <Tag/> |
O HTML envolvido por <code>
será exibido como é; somente o HTML que não estiver envolvido será analisado pelo Vue.
TIP
O HTML de saída é realizado por Markdown-it, enquanto os cabeçalhos processados são manipulados pelo VitePress (e usados tanto na barra lateral quanto no título do documento).
Escapes
Você pode escapar de interpolações Vue envolvendo-as em um <span>
ou outros elementos com a diretiva v-pre
:
Entrada
Isto <span v-pre>{{ será exibido como é }}</span>
Saída
Isto {{ será exibido como é }}
Alternativamente, você pode envolver todo o parágrafo em um container personalizado v-pre
:
::: v-pre
{{ Isto será exibido como é }}
:::
Output
{{ Isto será exibido como é }}
"Des-escape" em Blocos de Código
Por padrão, todos os blocos de código cercados são automaticamente envolvidos com v-pre
, então nenhuma sintaxe Vue será processada dentro deles. Para permitir a interpolação no estilo Vue dentro do cercado, você pode adicionar a linguagem com o sufixo -vue
, por exemplo, js-vue
:
Entrada
```js-vue
Olá {{ 1 + 1 }}
```
Saída
Olá 2
Observe que isso pode impedir que certos tokens sejam realçados corretamente.
Usando Pré-processadores CSS
O VitePress possui suporte embutido para pré-processadores CSS: arquivos .scss
, .sass
, .less
, .styl
e .stylus
. Não é necessário instalar plugins específicos do Vite para eles, mas o próprio pré-processador correspondente deve ser instalado:
# .scss e .sass
npm install -D sass
# .less
npm install -D less
# .styl e .stylus
npm install -D stylus
Então você pode usar o seguinte em Markdown e nos componentes do tema:
<style lang="sass">
.title
font-size: 20px
</style>
Usando Teleports
VitePress atualmente oferece suporte a SSG para teleports apenas para o corpo. Para outros alvos, você pode envolvê-los dentro do componente embutido <ClientOnly>
ou injetar a marcação de teleport na localização correta em sua página final HTML por meio do gancho postRender
.
Details
<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>