Slots com escopo no Vue.js
Em determinados cenários, é necessário acessar dados internos de um componente filho no conteúdo que o componente pai envia para ele. Um caso comum ocorre quando se tenta acessar dados definidos no filho diretamente dentro do corpo do componente pai. Considere o seguinte código:
Componente pai:
<div id="app">
<user>
<h3>Dados do usuário</h3>
<p>Nome: {{ user.name }}</p>
<p>Idade: {{ user.age }}</p>
</user>
</div>
Componente filho:
const app = Vue.createApp({});
app.component("user", {
data() {
return { user: { name: "Tom", age: 36 } };
},
template: `<div><slot></slot></div>`,
});
app.mount("#app");
Esse código não funciona porque o componente pai não tem acesso ao objeto user, que está definido apenas dentro do componente user
. As expressões {{ user.name }}
e {{ user.age }}
estão fora do escopo e, por isso, não produzem nenhum valor visível.
Para resolver esse tipo de situação, pode-se recorrer aos slots com escopo (scoped slots). Esse recurso permite que o componente filho envie dados ao conteúdo que o pai define dentro do slot. Os dados disponibilizados pelo filho ficam acessíveis apenas dentro desse escopo.
No componente pai, o slot é declarado dentro de um <template>
usando a diretiva v-slot
. Essa diretiva recebe um identificador que representa os dados enviados pelo componente filho.
A seguir, um exemplo funcional usando scoped slots:
<!DOCTYPE html>
<html>
<head>
<title>Slots Vue 3</title>
<meta charset="utf-8" />
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="app">
<user>
<template v-slot:default="props">
<h3>Dados do usuário</h3>
<p>Nome: {{ props.userinfo.name }}</p>
<p>Idade: {{ props.userinfo.age }}</p>
</template>
</user>
</div>
<script>
const app = Vue.createApp({});
app.component("user", {
data() {
return { user: { name: "Tom", age: 36 } };
},
template: `
<div>
<slot v-bind:userinfo="user"></slot>
</div>
`,
});
app.mount("#app");
</script>
</body>
</html>
Neste exemplo, o componente user
disponibiliza o objeto user
para o slot através de v-bind:userinfo="user"
. O componente pai define o conteúdo do slot padrão usando v-slot:default="props"
. Dessa forma, os dados são acessados por meio de props.userinfo
.
Como o slot não possui um nome explícito, o Vue o trata como default
, e a diretiva correspondente no pai é v-slot:default
. O identificador props
representa o objeto com os dados transmitidos e pode ter qualquer nome, desde que seja coerente com o uso interno.
Esse padrão também pode ser aplicado a listas, permitindo que o componente pai controle a estrutura visual de cada item:
<!DOCTYPE html>
<html>
<head>
<title>Slots Vue 3</title>
<meta charset="utf-8" />
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="app">
<userslist>
<template v-slot:userdetails="props">
<div>
<p>Nome: {{ props.userinfo.name }}</p>
<p>Idade: {{ props.userinfo.age }}</p>
</div>
</template>
</userslist>
</div>
<script>
const app = Vue.createApp({});
app.component("userslist", {
data() {
return {
users: [
{ name: "Tom", age: 36 },
{ name: "Sam", age: 39 },
{ name: "Bob", age: 25 },
],
};
},
template: `
<ul>
<li v-for="user in users">
<slot name="userdetails" v-bind:userinfo="user"></slot>
</li>
</ul>
`,
});
app.mount("#app");
</script>
</body>
</html>
O componente userslist
percorre o array users
e, para cada item, dispara o slot nomeado userdetails
, enviando o respectivo objeto pelo atributo v-bind:userinfo="user"
.
O componente pai define o conteúdo do slot userdetails
usando a diretiva v-slot:userdetails="props"
, acessando os dados de cada usuário por meio de props.userinfo
.
Esse padrão permite que o pai controle completamente a estrutura e a apresentação dos dados, enquanto o componente filho se responsabiliza apenas pela lógica de dados e repetição.
Resumo
- Scoped slots permitem que um componente filho envie dados ao conteúdo definido no slot pelo componente pai.
- O slot é declarado no pai com
<template v-slot:nome="variável">
. - Os dados são enviados pelo filho com
v-bind
dentro do slot. - Quando o slot não possui nome, o Vue o trata como
default
, e o pai deve usarv-slot:default
. - O pai pode acessar os dados enviados por meio do identificador declarado no
v-slot
. - Esse recurso oferece flexibilidade para controlar a estrutura visual no pai enquanto o filho gerencia os dados.
Documentação oficial: