6-Componentes en Laravel con el Ejemplo de Gestor de Tarea
Los componentes en Laravel son una forma poderosa de crear elementos reutilizables en tus vistas. Vamos a refactorizar el gestor de tareas usando componentes.
Tipos de Componentes en Laravel
Componentes de Clase: Más potentes, con lógica propia
Componentes Anónimos: Más simples, solo con vista
1. Refactorizando el Layout con Componentes
Componente Layout Principal (app/View/Components/AppLayout.php)
<?php
namespace App\View\Components;
use Illuminate\View\Component;
class AppLayout extends Component
{
public $titulo;
public function __construct($titulo = 'Gestor de Tareas')
{
$this->titulo = $titulo;
}
public function render()
{
return view('layouts.app');
}
}Vista del Layout (resources/views/layouts/app.blade.php)
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $titulo }}</title>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
<x-navbar />
<main class="container mx-auto px-4 py-6">
{{ $slot }}
</main>
<x-footer />
</body>
</html>2. Componente Navbar
Crear el componente
php artisan make:component NavbarComponente (app/View/Components/Navbar.php)
<?php
namespace App\View\Components;
use Illuminate\View\Component;
class Navbar extends Component
{
public function render()
{
return view('components.navbar');
}
}Vista del componente (resources/views/components/navbar.blade.php)
<nav class="bg-blue-600 text-white p-4 shadow-md">
<div class="container mx-auto flex justify-between items-center">
<a href="{{ route('tareas.index') }}" class="text-xl font-bold">GestorTareas</a>
<div class="space-x-4">
<a href="{{ route('tareas.index') }}" class="hover:underline">Inicio</a>
<a href="{{ route('tareas.crear') }}" class="hover:underline">Crear Tarea</a>
<a href="{{ route('salir') }}" class="hover:underline">Salir</a>
</div>
</div>
</nav>3. Componente Footer
php artisan make:component FooterVista del componente (resources/views/components/footer.blade.php)
<footer class="bg-gray-800 text-white py-6 mt-8">
<div class="container mx-auto text-center">
<p>Sistema de Gestión de Tareas © {{ date('Y') }}</p>
</div>
</footer>4. Componente para Mostrar Tareas
Crear componente de tarjeta de tarea
php artisan make:component TareaCard --viewVista del componente (resources/views/components/tarea-card.blade.php)
<div @class([
'border rounded-lg p-4 mb-4 shadow-sm',
'bg-green-50 border-green-200' => $tarea['completada'],
'bg-yellow-50 border-yellow-200' => !$tarea['completada']
])>
<h3 class="text-lg font-semibold">{{ $tarea['titulo'] }}</h3>
<p class="text-gray-600 my-2">{{ $tarea['descripcion'] }}</p>
<div class="flex justify-end space-x-2 mt-4">
<x-boton
href="{{ route('tareas.mostrar', $tarea['id']) }}"
color="blue">
Ver
</x-boton>
<x-boton
href="{{ route('tareas.eliminar', $tarea['id']) }}"
color="red">
Eliminar
</x-boton>
</div>
</div>5. Componente de Botón Reutilizable
Crear componente
php artisan make:component Boton --viewVista del componente (resources/views/components/boton.blade.php)
@props(['href' => null, 'color' => 'gray'])
@php
$colors = [
'blue' => 'bg-blue-600 hover:bg-blue-700',
'red' => 'bg-red-600 hover:bg-red-700',
'green' => 'bg-green-600 hover:bg-green-700',
'gray' => 'bg-gray-600 hover:bg-gray-700'
];
@endphp
@if($href)
<a href="{{ $href }}" @class([
'px-4 py-2 rounded text-white font-medium',
$colors[$color] ?? $colors['gray']
])>
{{ $slot }}
</a>
@else
<button @class([
'px-4 py-2 rounded text-white font-medium',
$colors[$color] ?? $colors['gray']
])>
{{ $slot }}
</button>
@endif6. Refactorizando las Vistas con Componentes
Vista Index (resources/views/tareas/index.blade.php)
<x-app-layout titulo="Lista de Tareas">
<div class="flex justify-between items-center mb-6">
<h1 class="text-2xl font-bold">Lista de Tareas</h1>
<x-boton href="{{ route('tareas.crear') }}" color="green">
Nueva Tarea
</x-boton>
</div>
@if(count($tareas) > 0)
<div class="space-y-4">
@foreach($tareas as $tarea)
<x-tarea-card :tarea="$tarea" />
@endforeach
</div>
@else
<div class="bg-white p-6 rounded-lg shadow text-center">
<p class="text-gray-600">No hay tareas registradas.</p>
</div>
@endif
</x-app-layout>Vista Crear Tarea (resources/views/tareas/crear.blade.php)
<x-app-layout titulo="Crear Nueva Tarea">
<div class="max-w-md mx-auto bg-white p-6 rounded-lg shadow">
<h2 class="text-xl font-semibold mb-4">Crear Nueva Tarea</h2>
<form action="{{ route('tareas.guardar') }}" method="POST">
@csrf
<div class="mb-4">
<label for="titulo" class="block text-gray-700 mb-2">Título</label>
<input type="text" id="titulo" name="titulo" required
class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<div class="mb-4">
<label for="descripcion" class="block text-gray-700 mb-2">Descripción</label>
<textarea id="descripcion" name="descripcion" rows="3"
class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"></textarea>
</div>
<div class="flex justify-end space-x-3">
<x-boton type="submit" color="blue">Guardar</x-boton>
<x-boton href="{{ route('tareas.index') }}" color="gray">Cancelar</x-boton>
</div>
</form>
</div>
</x-app-layout>Vista Mostrar Tarea (resources/views/tareas/mostrar.blade.php)
<x-app-layout titulo="Detalles de Tarea">
<div class="max-w-2xl mx-auto bg-white p-6 rounded-lg shadow">
<div @class([
'border-l-4 p-4 mb-6',
'border-green-500 bg-green-50' => $tarea['completada'],
'border-yellow-500 bg-yellow-50' => !$tarea['completada']
])>
<h2 class="text-2xl font-bold">{{ $tarea['titulo'] }}</h2>
<p class="text-gray-700 mt-2">{{ $tarea['descripcion'] }}</p>
<div class="mt-4 flex items-center">
<span @class([
'px-2 py-1 rounded-full text-xs font-medium',
'bg-green-200 text-green-800' => $tarea['completada'],
'bg-yellow-200 text-yellow-800' => !$tarea['completada']
])>
{{ $tarea['completada'] ? 'Completada' : 'Pendiente' }}
</span>
</div>
</div>
<div class="flex justify-end">
<x-boton href="{{ route('tareas.index') }}" color="gray">Volver</x-boton>
</div>
</div>
</x-app-layout>Ventajas de este Enfoque con Componentes
Reutilización de código: Los componentes como
<x-boton>se usan en múltiples lugaresConsistencia visual: Todos los botones y tarjetas tienen el mismo estilo
Mantenibilidad: Cambios en un componente se reflejan en toda la aplicación
Organización: Código mejor estructurado y separado por responsabilidades
Personalización: Los componentes aceptan props para modificar su comportamiento
Características implementadas:
Layout principal con componentes para navbar y footer
Componente reutilizable de botón con variantes de color
Componente de tarjeta de tarea con lógica condicional de clases
Sistema de slots para contenido dinámico
Props para personalizar componentes
Conditional classes con @class directive
Este enfoque con componentes hace que la aplicación sea más escalable y mantenible, siguiendo las mejores prácticas de Laravel y Blade.
Entendiendo los Slots en los Componentes de Laravel Blade
Los slots son una característica fundamental de los componentes en Laravel Blade que permiten inyectar contenido dinámico dentro de tus componentes. Son similares a los "children" en otros sistemas de componentes.
Conceptos Básicos de Slots
1. Slot Principal ($slot)
El slot principal es el contenido que se pasa entre las etiquetas de apertura y cierre del componente.
Ejemplo de uso:
<x-alert>
Este es el contenido que irá en el slot principal
</x-alert>En el componente (resources/views/components/alert.blade.php):
<div class="alert">
{{ $slot }} <!-- Aquí se renderizará el contenido -->
</div>2. Slots Nombrados
Permiten tener múltiples áreas de contenido en un componente.
Ejemplo de uso:
<x-card>
<x-slot name="header">
Título de la tarjeta
</x-slot>
Contenido principal de la tarjeta
<x-slot name="footer">
Pie de la tarjeta
</x-slot>
</x-card>Componente card.blade.php:
<div class="card">
<div class="card-header">
{{ $header }}
</div>
<div class="card-body">
{{ $slot }} <!-- Slot principal -->
</div>
<div class="card-footer">
{{ $footer }}
</div>
</div>Ejemplo Práctico con el Gestor de Tareas
1. Componente Layout con Slots
Componente app-layout (resources/views/layouts/app.blade.php):
<!DOCTYPE html>
<html>
<head>
<title>{{ $title ?? 'Gestor de Tareas' }}</title>
</head>
<body>
<x-navbar />
<main class="container">
<!-- Slot principal para el contenido específico de cada página -->
{{ $slot }}
</main>
<x-footer>
<!-- Slot con valor por defecto -->
<x-slot name="copyright">
© {{ date('Y') }} Gestor de Tareas
</x-slot>
</x-footer>
</body>
</html>2. Uso del Layout en una Vista
resources/views/tareas/index.blade.php:
<x-app-layout title="Lista de Tareas">
<!-- Este contenido va al slot principal -->
<h1>Mis Tareas</h1>
@foreach($tareas as $tarea)
<x-tarea-card :tarea="$tarea">
<!-- Slot adicional para acciones -->
<x-slot name="acciones">
<x-boton href="{{ route('tareas.mostrar', $tarea['id']) }}">
Ver Detalles
</x-boton>
</x-slot>
</x-tarea-card>
@endforeach
</x-app-layout>3. Componente TareaCard con Slots
resources/views/components/tarea-card.blade.php:
<div class="tarea {{ $tarea['completada'] ? 'completada' : 'pendiente' }}">
<h3>{{ $tarea['titulo'] }}</h3>
<p>{{ $tarea['descripcion'] }}</p>
<!-- Slot para contenido adicional -->
@isset($acciones)
<div class="acciones">
{{ $acciones }}
</div>
@endisset
<!-- Slot principal para cualquier otro contenido -->
{{ $slot }}
</div>Tipos de Slots Avanzados
1. Slots con Valores por Defecto
Puedes definir valores por defecto para los slots:
@props(['title' => 'Título por defecto'])
<h2>{{ $title }}</h2>
{{ $slot }}2. Slots Escopados
Pasas datos al slot como si fuera un componente:
<x-table :$users>
<x-slot:header column="nombre">
Nombre del Usuario
</x-slot:header>
</x-table>En el componente:
@props(['users'])
<table>
<thead>
<tr>
{{ $header(['column' => 'nombre']) }}
</tr>
</thead>
<!-- ... -->
</table>Buenas Prácticas con Slots
Usa slots nombrados para contenido complejo con múltiples secciones
Mantén los slots simples - si necesitas mucha lógica, considera dividir en más componentes
Documenta los slots disponibles en componentes complejos con comentarios
Usa valores por defecto para hacer componentes más flexibles
Considera slots escopados cuando necesites pasar datos al contenido del slot
Los slots son una herramienta poderosa en Laravel Blade que te permite crear componentes altamente reutilizables y flexibles, manteniendo un código limpio y organizado
Comentarios
Publicar un comentario