Si tu componente acepta slots, en ocasiones querrás comprobar si se han suministrado (o no). ¿Por qué?, por varias
razones. Es posible que quieras añadir estilos específicos usando un div
como wrapper y asegurarte que
no lo renderizas si no hay contenido —slot— que mostrar, evitando un elemento HTML vacío.
De ahí lo de renderizado condicional.
Comprobar si existe contenido para un slot
Ahora bien. ¿cómo conseguirlo?. Con Options API es muy sencillo ya que todos los slots de un
componente están disponibles en el objeto $slots
. Si tu
componente tiene al menos un slot, estará disponible bajo $slots.default
. Si tiene más de un slot, invocando $slots
obtendrás un array de VNodes
usando sus nombres como key.
Teniendo esto claro, podemos comprobar si existe contenido para un slot y decidir qué hacer.
<!-- MyComponent.vue instantiation-->
<MyComponent>
<p>Slot content</p>
</MyComponent>
<!-- MyComponent.vue -->
<template>
<div>
<h1>Slots FTW 🔥</h1>
<div v-if="$slots.default" class="">
<slot />
</div>
<slot name="one" />
<slot name="two" />
</div>
</template>
Caso práctico con la Composition API
Hace poco me encontré con un escenario donde quería utilizar un componente de forma recursiva. La diferencia entre implementaciones es que en algunos casos se le pasará contenido a su slot y en otros no.
Por simplicidad he creado una pequeña demo donde tenemos un componente llamado TableRow.vue
que acepta un slot. Dentro
del componente, podemos acceder a la lista de slots con
el helper useSlots
y, con una propiedad computada,
decidir si renderizar su contenido o no.
import { useSlots, computed } from 'vue';
const slots = useSlots();
const hasExtraContent = computed(() => !!slots.extra);
Si es la primera vez que ves el operador !!
(en realidad no es un operador es el operador !
dos veces) doble
exclamación no te preocupes, el primer !
convierte el valor en la versión booleana contraria, mientras que el
segundo !
invierte el valor booleano. Es una manera ***moderna******* de convertir un objeto en su Boolean
equivalente. Boolean()
realiza la misma acción.
Ahora podemos usar hasExtraContent
para comprobar si el slot extra
tiene contenido.
<template>
<div class="file">
...
<div v-if="hasExtraContent">
<slot name="extra" />
</div>
...
</div>
</template>