
Construindo componentes altamente reutilizáveis com Vue Slots
Data de Publicação: 5 de agosto de 2021
VueJS
Como a própria documentação do Vuejs já diz, Slot é um recurso que nos permite inserir elementos dentro de um componente. Desta forma é possível criar um componente mais genérico e reutilizá-lo várias vezes dentro da aplicação mudando seu conteúdo interno.
Introdução
O Vuejs é um framework muito robusto que oferece vários recursos interessantes, conhecer estes recursos é essencial para que possamos construir aplicações com mais velocidade e manter um bom padrão de código. Neste post vou falar um pouco sobre o recurso de Slots e mostrar alguns exemplos de quando podemos usá-lo.
Quando devo utilizar Slots
Os Slots geralmente são utilizados quando estamos construindo algum componente que precisa exibir um conteúdo dinâmico, como por exemplo: Modais, Data Tables e Cards. Porém é possível ir além destes casos e criar algo como layouts para serem utilizados nas páginas da aplicação.
Imagine que você esteja trabalhando em um projeto com outros desenvolvedores, o que é o cenário mais comum. Uma vez que foi definida a identidade visual da aplicação não faz sentido toda vez que for criar uma nova tela repedir o mesmo código para aplicar o "layout base" da página para só então começar a pensar na regra de negócio da tela em questão. Isso toma muito tempo de desenvolvimento, além de deixar o código poluído dificultando a manutenção. O ideal seria criar um componente que aplique a identidade visual e injetar o conteúdo da tela através de slots.
Tipos de Slot
Antes de partirmos para o código é preciso entender os tipos de slot, então abaixo explicarei melhor sobre eles.
Default Slot
Por padrão se criarmos um slot sem atribuir um nome ele será interpretado pelo Vue como o slot padrão. Esta é a forma mais simples de se usar slots e lembra bastante a sintaxe do React. Por exemplo, imagine que você está criando um componente de modal e deseja utilizá-lo desta forma:
<my-modal v-if="isVisible">
<div class="modal-content">
<p>Este é o conteúdo do modal</p>
</div>
</my-modal>
Para que o conteúdo declarado entre as tags do componente seja injetado dentro dele é preciso usar o slot padrão da seguinte forma:
<template>
<div class="modal">
<div class="modal__content">
<slot />
</div>
</div>
</template>
Onde a tag <slot />
seria substituída pelo conteúdo.
Named Slot
Os named slots funcionam de forma bem parecida, porém eles nos permitem utilizar mais de um slot por componente. Continuando com o exemplo acima, imagine que agora você quer criar uma sessão separada para o título e outra para os botões de ação. A implementação do componente ficaria assim:
<template>
<div class="modal">
<div class="modal__title">
<slot name="title" />
</div>
<div class="modal__content">
<slot />
</div>
<div class="modal__footer">
<slot name="actions" />
</div>
</div>
</template>
E para utilizar os novos slots você teria que fazer da seguinte forma:
<my-modal v-if="isVisible">
<template #title>
<h3>Título do Modal</h3>
</template>
<template #default>
<p>Este é o conteúdo do modal</p>
</template>
<template #actions>
<button type="button" class="btn" @click="cancelar()">Cancelar</button>
<button type="button" class="btn" @click="salvar()">Confirmar</button>
</template>
</my-modal>
Exemplo prático
Agora finalmente vamos para a parte interessante. Vou te mostrar como criar um layout base para as páginas da sua aplicação usando slots, então abra seu terminal e seu editor de códigos favorito.
Primeiramente crie um novo projeto Vue com o comando:
vue create nome-do-projeto
Selecione a primeira opção Default ([Vue 2], babel, eslint)
e aguarde até que a instalação das dependências seja concluída.
Agora que o projeto está criado vamos começar a construir nosso componente de layout.
Crie o arquivo BaseLayout.vue
dentro de src/components
e cole o seguinte código dentro dele:
<template></template>
<script>
export default {}
</script>
<style></style>
A estrutura html do componente ficará da seguinte forma:
<template>
<div class="base-layout">
<div class="base-layout__title">
<slot name="title" />
</div>
<div class="base-layout__breadcrumb">
<slot name="breadcrumb" />
</div>
<div class="base-layout__content">
<slot />
</div>
</div>
</template>
Agora vamos adicionar um pouco de css para definir o layout do componente:
<style>
.base-layout {
width: 97.9%;
height: 96.6vh;
padding: 16px;
display: flex;
flex-direction: column;
background: #fafafa;
}
.base-layout__title {
width: 100%;
padding: 16px 0;
}
.base-layout__title h1, .base-layout__title h2, .base-layout__title h3 {
margin: 0;
padding: 0;
color: rgba(0, 0, 0, 0.75);
}
.base-layout__title h1 {
font-size: 2rem;
}
.base-layout__title h2 {
font-size: 1.8rem;
}
.base-layout__title h3 {
font-size: 1.6rem;
}
.base-layout__breadcrumb {
width: 100%;
padding: 16px 0;
border-top: 1px solid #ededed;
border-bottom: 1px solid #ededed;
}
.base-layout__content {
height: 82%;
display: flex;
flex-direction: column;
background: #fff;
border: 1px solid #ededed;
border-radius: 6px;
margin-top: 20px;
padding: 16px;
}
</style>
Por fim, abra o arquivo App.vue
, apague todo o conteúdo e substitua pelo código abaixo:
<template>
<base-layout>
<template #title>
<h3>Título da Página</h3>
</template>
<template #breadcrumb> Home / Página Customizada </template>
<template #default>
<p>Este é o conteúdo da página</p>
</template>
</base-layout>
</template>
<script>
import BaseLayout from './components/BaseLayout.vue'
export default {
name: 'App',
components: {
BaseLayout,
},
}
</script>
<style>
body {
margin: 0;
padding: 0;
box-sizing: border-box;
}
</style>
E este é o resultado final:

Dica Bonus
É possível renderizar as sessões do layout apenas se o slot for utilizado, evitando assim que as sessões sejam renderizadas sem nenhum conteúdo. para fazer isso basta adicionar a seguinte verificação:
<div v-if="$slots.breadcrumb" class="base-layout__breadcrumb">
<slot name="breadcrumb" />
</div>