Skip to content

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

md
{{ 1 + 1 }}

Saída

2

Diretivas

Diretivas também funcionam (observe que, por definiçào, HTML cru também é válido em Markdown):

Entrada

html
<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:

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

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

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

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

Saída

json
{
  "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:

md
<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:

MarkdownHTML de SaídaCabeçalho Processado
 # texto <Tag/> 
<h1>texto <Tag/></h1>texto
 # texto `<Tag/>` 
<h1>texto <code>&lt;Tag/&gt;</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

md
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:

md
::: 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

md
```js-vue
Olá {{ 1 + 1 }}
```

Saída

js
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:

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

Lançado sob licença MIT