Components Blade
Com crear components reutilitzables amb Blade: components de classe, anònims, slots i props.
Què són els components?#
Els components Blade permeten crear peces d'interfície reutilitzables amb la seva pròpia lògica i presentació. Pensa en un component com una etiqueta HTML personalitzada: en lloc d'escriure <div class="alert alert-success">...</div> cada cop, pots crear un component <x-alert> que encapsuli tota aquesta estructura.
Hi ha dos tipus de components: els components de classe, que tenen una classe PHP associada per a lògica més complexa, i els components anònims, que són simplement fitxers Blade sense classe.
Components de classe#
Per crear un component de classe, utilitza la comanda Artisan:
php artisan make:component AlertAixò genera dos fitxers. La classe PHP a app/View/Components/Alert.php conté la lògica del component, i la vista Blade a resources/views/components/alert.blade.php conté el seu HTML.
La classe del component defineix les propietats que el component accepta. Les propietats del constructor es converteixen automàticament en atributs que pots passar des de la vista:
// app/View/Components/Alert.php
namespace App\View\Components;
use Illuminate\View\Component;
class Alert extends Component
{
public function __construct(
public string $type = 'info',
public string $message = ''
) {}
public function alertClass(): string
{
return match ($this->type) {
'success' => 'bg-green-100 text-green-800 border-green-300',
'error' => 'bg-red-100 text-red-800 border-red-300',
'warning' => 'bg-yellow-100 text-yellow-800 border-yellow-300',
default => 'bg-blue-100 text-blue-800 border-blue-300',
};
}
public function render()
{
return view('components.alert');
}
}A la vista del component, les propietats públiques de la classe i els seus mètodes estan disponibles directament:
{{-- resources/views/components/alert.blade.php --}}
<div class="p-4 rounded-lg border {{ $alertClass() }}">
@if($message)
<p>{{ $message }}</p>
@else
{{ $slot }}
@endif
</div>L'avantatge dels components de classe és que pots encapsular lògica complexa al mètode PHP en lloc de posar-la a la vista. El mètode alertClass() determina les classes CSS segons el tipus, mantenint la vista neta.
Utilitzar components#
Per utilitzar un component, escriu-lo com una etiqueta HTML amb el prefix x-. Els atributs de l'etiqueta es passen com a propietats al constructor de la classe:
{{-- Amb l'atribut message --}}
<x-alert type="success" message="Operació completada!" />
{{-- Amb contingut al slot --}}
<x-alert type="warning">
<strong>Atenció:</strong> Aquesta acció és irreversible.
</x-alert>
{{-- Amb el valor per defecte (type='info') --}}
<x-alert message="Informació general." />Quan passes una variable o expressió PHP com a atribut, utilitza el prefix : per indicar que el valor és codi PHP i no un string literal:
{{-- String literal --}}
<x-alert type="success" />
{{-- Expressió PHP --}}
<x-alert :type="$alertType" :message="$user->name . ' creat correctament'" />Components anònims#
Quan un component no necessita lògica complexa, pots crear-lo sense classe PHP. Simplement crea un fitxer Blade a resources/views/components/ i utilitza la directiva @props per declarar les propietats:
{{-- resources/views/components/button.blade.php --}}
@props(['type' => 'button', 'color' => 'blue', 'size' => 'md'])
<button type="{{ $type }}"
class="btn btn-{{ $color }} btn-{{ $size }} rounded font-medium">
{{ $slot }}
</button>L'ús és idèntic als components de classe:
<x-button color="red">Eliminar</x-button>
<x-button type="submit" color="green" size="lg">Desar</x-button>La directiva @props fa dues coses: declara les propietats del component amb els seus valors per defecte, i les extreu de la llista d'atributs HTML. Qualsevol atribut que passis i que no estigui a @props estarà disponible a través de la variable $attributes.
L'objecte $attributes#
L'objecte $attributes conté tots els atributs HTML passats al component que no estan declarats a @props. Això és molt útil per permetre que l'usuari del component afegeixi classes CSS, IDs o atributs data personalitzats:
{{-- resources/views/components/input.blade.php --}}
@props(['label', 'name', 'type' => 'text'])
<div class="mb-4">
<label for="{{ $name }}" class="block text-sm font-medium">
{{ $label }}
</label>
<input type="{{ $type }}"
name="{{ $name }}"
id="{{ $name }}"
{{ $attributes->merge(['class' => 'w-full border rounded px-3 py-2']) }}>
</div>{{-- Ús: la classe 'border-red-500' es fusiona amb les classes per defecte --}}
<x-input label="Email" name="email" type="email" class="border-red-500" />El mètode merge() fusiona les classes CSS que l'usuari passa amb les classes per defecte del component. Pots fer servir class() per a condicions de classes:
<input {{ $attributes->class([
'w-full border rounded px-3 py-2',
'border-red-500' => $errors->has($name),
]) }}>Slots#
El $slot per defecte conté tot el contingut que poses entre les etiquetes d'obertura i tancament del component. Però sovint necessites múltiples zones de contingut. Per a això, utilitza els slots amb nom:
{{-- resources/views/components/card.blade.php --}}
<div class="bg-white rounded-lg shadow overflow-hidden">
@if(isset($header))
<div class="px-6 py-4 bg-gray-50 border-b">
{{ $header }}
</div>
@endif
<div class="px-6 py-4">
{{ $slot }}
</div>
@if(isset($footer))
<div class="px-6 py-3 bg-gray-50 border-t text-right">
{{ $footer }}
</div>
@endif
</div>Per omplir els slots amb nom, utilitza l'etiqueta <x-slot> amb l'atribut :name:
<x-card>
<x-slot:header>
<h2 class="text-lg font-bold">Detalls de l'usuari</h2>
</x-slot:header>
<p>Nom: {{ $user->name }}</p>
<p>Email: {{ $user->email }}</p>
<p>Registrat: {{ $user->created_at->format('d/m/Y') }}</p>
<x-slot:footer>
<x-button color="blue">Editar</x-button>
<x-button color="red">Eliminar</x-button>
</x-slot:footer>
</x-card>Fixa't que el contingut que no està dins de cap <x-slot> va al $slot per defecte. Els slots amb nom ($header, $footer) es comproven amb isset() per renderitzar-los condicionalment.
Components dins de subdirectoris#
Per a projectes grans, pots organitzar els components en subdirectoris. Un component a resources/views/components/form/input.blade.php s'utilitza amb punts:
<x-form.input label="Nom" name="name" />
<x-form.select label="País" name="country" :options="$countries" />Components inline#
Per a components molt petits, pots crear-los sense fitxer de vista. El mètode render() retorna el HTML directament:
php artisan make:component Badge --inlineclass Badge extends Component
{
public function __construct(
public string $color = 'blue'
) {}
public function render()
{
return <<<'blade'
<span class="px-2 py-1 text-xs rounded-full bg-{{ $color }}-100 text-{{ $color }}-800">
{{ $slot }}
</span>
blade;
}
}