Vue.js: Slots
Última atualização: 2026-10-20
Os slots fazem parte da API de Distribuição de Conteúdo do Vue — os componentes pais podem inserir qualquer conteúdo nos “slots” de um componente filho. Os slots tornam os componentes tão flexíveis quanto os “modelos”: os componentes pais controlam o que é exibido, enquanto os componentes filhos controlam onde isso é exibido.
O Vue 3 oferece três tipos de slots: slots padrão, slots nomeados e slots com escopo. Esta lição vai ajudá-lo a dominar o uso e as melhores práticas para esses três tipos.
1. O que você vai aprender
- Uso básico do slot padrão
<slot /> - Abreviações para os slots denominados
<slot name="header" />ev-slot:header - Slots de escopo: os componentes filhos passam dados para os slots do componente pai
<template v-slot>Sintaxe (Vue 2.6+)- Sintaxe de nomes e abreviações dinâmicos de slots
- Conteúdo padrão do slot (conteúdo alternativo)
$slots/useSlotshook
2. O desafio de não poder personalizar o conteúdo de um componente de cartão
(1) Desafio: 5 estilos de cartão, exigindo a criação de 5 componentes
O administrador do site de comércio eletrônico da Alice precisava de 5 tipos de cartões:
<!-- ❌ The "Broken" Version:5 component -->
<!-- ProductCard.vue -->
<div class="card">{{ product.name }}</div>
<!-- UserCard.vue -->
<div class="card">{{ user.name }}</div>
<!-- OrderCard.vue -->
<div class="card">Order #{{ order.id }}</div>
<!-- 5 component,90% The code is the same,The only difference is the content -->
O gerente de produto Charlie:
“Alice, preciso de mais 5 tipos de cartão na próxima semana. Não podemos ficar adicionando novos componentes. Precisamos de um cartão flexível que aceite qualquer tipo de conteúdo.”
(2) Solução com slots do Vue: 1 BaseCard, com conteúdo fornecido pelo componente pai
1 BaseCard.vue → uma variedade infinita de cartões. Sempre que você adicionar um novo, basta escrever o conteúdo — não é preciso modificar o componente.
(3) Receita
Após usar os slots:
- Número de componentes: 5 → 1 (-80%)
- Novo tipo de cartão: 1 linha de código de template
- Custos de manutenção: basta alterar um estilo para que mais de 5 cartões sejam atualizados simultaneamente
- Reutilização: O BaseCard pode ser utilizado em todos os cenários relacionados a cartões
3. Slot padrão
(1) Uso básico
Resultados da renderização:
<div class="card">
<h3>Hello</h3>
<p>This is the card content</p>
</div>
(2) Conteúdo padrão (alternativo)
<!-- The parent component does not pass content -->
<BaseCard />
<!-- Rendering:<p>No content provided</p> -->
<!-- Passing Content from the Parent Component -->
<BaseCard>
<p>Custom content</p>
</BaseCard>
<!-- Rendering:<p>Custom content</p>(Override Default)-->
(3) 5 principais casos de uso
| Cenário | Uso |
|---|---|
| Conteúdo do cartão | <slot /> |
| Texto do botão | <slot /> |
| Item da lista | <slot :item="item" /> |
| Campo do formulário | <slot /> |
| Corpo da caixa modal | <slot /> |
▶ Exemplo: BaseCard.vue (padrão + slots nomeados)
▶ ExperimenteSaída:
<BaseCard> sem conteúdo → "No content" no corpo
Com #header → cabeçalho "Product Name"
Com #footer → rodapé com "View Details"
4. Slots nomeados
(1) Definição de slots nomeados
(2) Como usar componentes pai (3 sintaxes)
(3) Nomes dinâmicos de slots
(4) Verifique se há um encaixe
5. Espaços para miras telescópicas
(1) Ponto-chave: os componentes filhos passam dados para os slots do componente pai
Resultados da renderização:
<ul>
<li><p>1. Alice (alice@example.com)</p></li>
<li><p>2. Bob (bob@example.com)</p></li>
<li><p>3. Charlie (charlie@example.com)</p></li>
</ul>
(2) 5 Padrões de encaixe para miras telescópicas
| Padrão | Implementação do componente pai | Finalidade |
|---|---|---|
| Aceita todos os props | <template #default="slotProps"> |
Aceita o objeto inteiro |
| Desconstrução | <template #default="{ user }"> |
Use apenas os campos de que você precisa |
| Renomear | <template #default="{ user: u }"> |
Evitar conflitos de variáveis |
| Valor padrão | <template #default="{ user = defaultUser }"> |
Forneça um valor padrão durante a desconstrução |
| Sem modelo | {{ slotProps.user.name }} |
Cenário simples (espaço padrão) |
(3) Exemplo completo: Lista personalizável
▶ Experimente▶ Exemplo: Exemplo completo de slots de escopo
▶ ExperimenteSaída:
Tabela com as colunas de columns e uma linha por item de data
#cell-status → <span class="badge active">active</span>
#cell-actions → botão Edit em cada linha
6. $slots e useSlots
(1) $slots Acesso aos slots
(2) useSlots (API de Composição)
<script setup>
import { useSlots } from 'vue'
const slots = useSlots()
// Check if the slot exists
if (slots.header) {
console.log('Header slot exists')
}
// Dynamic Rendering
if (slots.default) {
console.log('Default slot exists')
}
</script>
(3) $slots x useSlots
| Dimensão | $slots |
useSlots() |
|---|---|---|
| Tipo de API | Usada diretamente nos modelos | Usada em JS (API de Composição) |
| Voltar | Objeto Slot | Objeto Slot (formato refs) |
| Cena | Dentro do modelo | Dentro de <script setup> |
▶ Exemplo: 5 Principais usos de $slots
▶ ExperimenteSaída:
slots.header existe → "Has header"
Object.keys(slots) → cada nome renderizado via <slot :name="name" />
Sem slot default → "Default fallback"
7. Exercício abrangente: 5 maneiras de usar o BaseCard
▶ Exemplo: 5 maneiras de usar o BaseCard
▶ ExperimenteSaída:
1. Só corpo → "Simple content"
3. header + body + footer → "Order #12345", "Total: $99.99", botão
5. Slot de escopo → Edit/Delete recebem { user }
(1) 📊 4. Referência rápida para 5 erros comuns
| Erro | Sintoma | Solução |
|---|---|---|
| Nome do slot com erro ortográfico | Conteúdo não exibido | Verifique se <slot name="..."> e #name correspondem |
| Vários elementos raiz no componente pai | Aviso | O componente pai está envolto em <template #name> |
| v-slot (sintaxe antiga) | Compatível com o Vue 2 | Use v-slot:header ou #header em vez disso |
| Slot padrão não passado | Componente pai não exibido | Verifique o conteúdo <Component /> no componente pai |
| Os slots de escopo não são desestruturados | Os modelos são prolixos | Desestruturação com { user, index } |
(2) 📊 5. 5 Comparações de desempenho
| Sintaxe | Compilação | Desempenho | Recomendações |
|---|---|---|---|
<slot /> |
Estático | ⭐⭐⭐⭐⭐ | Padrão |
<slot name="x" /> |
Estático | ⭐⭐⭐⭐⭐ | Nomeado |
<slot :x="x" /> |
Estático | ⭐⭐⭐⭐ | Alcance |
v-if="$slots.x" |
Condição | ⭐⭐⭐⭐ | Detectado |
useSlots() |
Tempo de execução | ⭐⭐⭐ | Usado em JS |
❓ Perguntas Frequentes
v-slot e a forma abreviada #?#header is a shorthand for v-slot:header. Recomendamos usar a forma abreviada (é mais concisa).<slot /> é o valor padrão. Se for absolutamente necessário nomeá-lo, use <slot name="default" />; o componente pai pode usar <template #default> ou simplesmente passar o conteúdo diretamente.<slot>.$slots (modelo) ou useSlots() (JS). O componente filho expõe o slot usando <slot>, e o componente pai o preenche usando <template #name>.<slot name="header"><h3>Default Header</h3></slot>. Esse conteúdo é exibido quando o componente pai não passa um cabeçalho.📖 Resumo
- Os slots são a API de distribuição de conteúdo do Vue: os componentes pai controlam o conteúdo, enquanto os componentes filhos controlam o posicionamento
- 3 tipos de slots: slot padrão (
<slot />), slot nomeado (name="x") e slot com escopo (:x="x") - O componente pai passa um slot nomeado usando
<template #name>ou a abreviação#name - Os slots de escopo permitem que os componentes filhos transmitam dados aos componentes pais (propriedades de slot)
<slot>Conteúdo padrão (alternativo) exibido quando o componente pai não passa nenhum conteúdo$slots/useSlots()Verificar se o slot existe- Trabalhando com slots e props: os props passam a configuração, enquanto os slots passam o conteúdo
📝 Exercícios
-
Questões básicas (Dificuldade: ⭐)
Implemente um componente Button simples:
- BaseButton.vue: Slot padrão + 3 variantes (principal/sucesso/perigo)
- props:
variant(String) - Componente pai: Testar 3 variantes + conteúdo personalizado do slot
-
Problemas avançados (Dificuldade: ⭐⭐)
Implemente o componente BaseLayout:
- Componentes filhos: 3 slots nomeados (cabeçalho / padrão / rodapé)
- Componente pai: use o BaseLayout para implementar a página do painel
- Use
$slotspara verificar se o slot existe - Adicionar conteúdo padrão (alternativo)
-
Problema de desafio (Dificuldade: ⭐⭐⭐)
Implementar um sistema completo de componentes DataTable:
- DataTable.vue: Recebe colunas + dados e renderiza a tabela
- Espaço de escopo:
#cell-{key}Permite que os componentes pai personalizem as células - Slot padrão: exibe o valor original quando o componente pai não fornece um
- Exemplo de componente pai: Tabela de usuários + Tabela de pedidos — Dois métodos diferentes de exibição de colunas
- Desempenho: o v-memo armazena as linhas em cache (evita a redesenho quando os dados permanecem inalterados)
- Tipagem forte do TypeScript