Implementación de Slots en Componentes Vue.js

Slots por Defecto

Los slots por defecto permiten insertar contenido genérico en un componente hijo. Si no se proporciona contenido, se usa el valor predeterminado definido en el slot.

<!-- Definición del componente MiBoton -->
<template>
  <button>
    <em><slot>Enviar</slot></em>
  </button>
</template>

<!-- Uso en el componente padre -->
<template>
  <MiBoton>Guardar</MiBoton>
</template>

Slots con Nombre

Los slots con nombre permiten distribuir contenido en múltiples secciones específicas dentro de un componente. Se utilizan atributos como name para identificar cada slot.

<!-- Definición del componente Contenedor -->
<template>
  <div class="contenedor-cabecera">
    <slot name="cabecera"></slot>
  </div>
  <div class="contenedor-cuerpo">
    <slot name="cuerpo"></slot>
  </div>
  <div class="contenedor-pie">
    <slot name="pie"></slot>
  </div>
</template>

<!-- Uso en el componente padre -->
<template>
  <Contenedor>
    <template #cabecera>
      <div class="fondo-azul texto-blanco">Encabezado del contenido</div>
    </template>
    <template #cuerpo>
      <div class="fondo-gris texto-rojo">Sección principal</div>
    </template>
    <template #pie>
      <div class="fondo-verde texto-azul">Información de pie</div>
    </template>
  </Contenedor>
</template>

Nombres de Slots Dinámicos

Se pueden asignar nombres de slots de forma dinámica usando directivas como v-slot con una variable reactiva.

<template v-slot:[nombreSlotDinamico]>...</template>

Acceso a Datos en Slots

Por defecto, el contneido dentro de un slot no puede acceder a los datos del componente hijo; solo tiene acceso al ámbito del componente padre. Sin embargo, es posible exponer datos del componente hijo mediante atributos en el slot.

<!-- Definición del componente Articulo -->
<template>
  <div class="seccion-cabecera">
    <slot name="cabecera" :titulo="contenido.titulo" :fecha="contenido.fecha"></slot>
  </div>
  <div class="seccion-cuerpo">
    <slot name="cuerpo" :texto="contenido.texto"></slot>
  </div>
  <div class="seccion-pie">
    <slot name="pie" :derechos="contenido.derechos"></slot>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const contenido = ref({
  titulo: 'Mi Artículo',
  fecha: '2023-10-01',
  texto: 'Contenido detallado aquí.',
  derechos: 'Todos los derechos reservados.'
});
</script>

<!-- Uso en el componente padre -->
<template>
  <Articulo>
    <template #cabecera="datosCabecera">
      <div class="fondo-primario texto-blanco">{{ datosCabecera.titulo }}</div>
    </template>
    <template #cuerpo="datosCuerpo">
      <div class="fondo-secundario texto-rojo">{{ datosCuerpo.texto }}</div>
    </template>
    <template #pie="datosPie">
      <div class="fondo-info texto-primario">{{ datosPie.derechos }}</div>
    </template>
  </Articulo>
</template>

Es importente notar que los datos expuestos desde el componente hijo son de solo lectura en el contexto del slot padre. No se pueden modificar directamente desde el contenido del slot.

Función useSlots()

En el script de un componente, se puede usar useSlots() de Vue para verificar si se han proporcionado slots específicos desde el componente padre. Esto es útil para lógica condicional basada en la presencia de slots.

<!-- Componente Interno -->
<template>
  <div>
    <slot />
    <slot name="adicional" />
  </div>
</template>

<script lang="ts" setup>
import { useSlots } from 'vue';

// Verificar si el slot por defecto tiene contenido
const tieneSlotDefault = !!useSlots().default;
// Verificar si el slot 'adicional' tiene contenido
const tieneSlotAdicional = !!useSlots().adicional;
</script>

Etiquetas: vue.js Slots Vue Componentes Vue Reactividad Vue Template Syntax Vue

Publicado el 6-12 21:35