Plantillas Blade
Introducción
Blade es el motor de plantillas simple pero poderoso que se incluye con Laravel. A diferencia de algunos motores de plantillas PHP, Blade no te restringe de usar código PHP simple en tus plantillas. De hecho, todas las plantillas Blade se compilan en código PHP simple y se almacenan en caché hasta que se modifican, lo que significa que Blade agrega esencialmente cero sobrecarga a tu aplicación. Los archivos de plantilla Blade usan la extensión .blade.php
y generalmente se almacenan en el directorio resources/views
.
Las vistas Blade pueden ser devueltas desde rutas o controladores usando el helper global view
. Por supuesto, como se menciona en la documentación sobre vistas, los datos pueden ser pasados a la vista Blade usando el segundo argumento del helper view
:
Route::get('/', function () {
return view('greeting', ['name' => 'Finn']);
});
Supercargando Blade con Livewire
¿Quieres llevar tus plantillas Blade al siguiente nivel y construir interfaces dinámicas con facilidad? Echa un vistazo a Laravel Livewire. Livewire te permite escribir componentes Blade que se complementan con funcionalidad dinámica que típicamente solo sería posible a través de frameworks frontend como React o Vue, proporcionando un gran enfoque para construir frontends modernos y reactivos sin las complejidades, renderizado del lado del cliente o pasos de construcción de muchos frameworks JavaScript.
Mostrando Datos
Puedes mostrar datos que se pasan a tus vistas Blade envolviendo la variable en llaves rizadas. Por ejemplo, dada la siguiente ruta:
Route::get('/', function () {
return view('welcome', ['name' => 'Samantha']);
});
Puedes mostrar el contenido de la variable name
así:
Hello, {{ $name }}.
Las declaraciones de eco de Blade {{ }}
se envían automáticamente a través de la función htmlspecialchars
de PHP para prevenir ataques XSS.
No estás limitado a mostrar el contenido de las variables pasadas a la vista. También puedes mostrar los resultados de cualquier función PHP. De hecho, puedes poner cualquier código PHP que desees dentro de una declaración de eco de Blade:
The current UNIX timestamp is {{ time() }}.
Codificación de Entidades HTML
Por defecto, Blade (y la función e
de Laravel) codificará doblemente las entidades HTML. Si deseas desactivar la codificación doble, llama al método Blade::withoutDoubleEncoding
desde el método boot
de tu AppServiceProvider
:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Inicializar cualquier servicio de la aplicación.
*/
public function boot(): void
{
Blade::withoutDoubleEncoding();
}
}
Mostrando Datos sin Escapar
Por defecto, las declaraciones {{ }}
de Blade se envían automáticamente a través de la función htmlspecialchars
de PHP para prevenir ataques XSS. Si no deseas que tus datos sean escapados, puedes usar la siguiente sintaxis:
Hello, {!! $name !!}.
Ten mucho cuidado al mostrar contenido que es proporcionado por los usuarios de tu aplicación. Normalmente deberías usar la sintaxis escapada de doble llave rizada para prevenir ataques XSS al mostrar datos proporcionados por el usuario.
Blade y Frameworks JavaScript
Dado que muchos frameworks JavaScript también usan «llaves» para indicar que una expresión dada debe mostrarse en el navegador, puedes usar el símbolo @
para informar al motor de renderizado de Blade que una expresión debe permanecer intacta. Por ejemplo:
<h1>Laravel</h1>
Hello, @{{ name }}.
En este ejemplo, el símbolo @
será eliminado por Blade; sin embargo, la expresión {{ name }}
permanecerá intacta por el motor de Blade, permitiendo que sea renderizada por tu framework JavaScript.
El símbolo @
también puede ser usado para escapar directivas de Blade:
<!-- Plantilla Blade -->
@@if()
<!-- Salida HTML -->
@if()
Renderizando JSON
A veces puedes pasar una matriz a tu vista con la intención de renderizarla como JSON para inicializar una variable JavaScript. Por ejemplo:
<script>
var app = <?php echo json_encode($array); ?>;
</script>
Sin embargo, en lugar de llamar manualmente a json_encode
, puedes usar la directiva Illuminate\Support\Js::from
. El método from
acepta los mismos argumentos que la función json_encode
de PHP; sin embargo, asegurará que el JSON resultante esté correctamente escapado para su inclusión dentro de comillas HTML. El método from
devolverá una declaración JSON.parse
de JavaScript que convertirá el objeto o matriz dado en un objeto JavaScript válido:
<script>
var app = {{ Illuminate\Support\Js::from($array) }};
</script>
Las versiones más recientes del esqueleto de la aplicación Laravel incluyen un facade Js
, que proporciona acceso conveniente a esta funcionalidad dentro de tus plantillas Blade:
<script>
var app = {{ Js::from($array) }};
</script>
Solo debes usar el método Js::from
para renderizar variables existentes como JSON. La plantilla Blade se basa en expresiones regulares y los intentos de pasar una expresión compleja a la directiva pueden causar fallos inesperados.
La Directiva @verbatim
Si estás mostrando variables JavaScript en una gran parte de tu plantilla, puedes envolver el HTML en la directiva @verbatim
para que no tengas que prefijar cada declaración de eco de Blade con un símbolo @
:
@verbatim
<div class="container">
Hello, {{ name }}.
</div>
@endverbatim
Directivas de Blade
Además de la herencia de plantillas y la visualización de datos, Blade también proporciona atajos convenientes para las estructuras de control PHP comunes, como las declaraciones condicionales y los bucles. Estos atajos proporcionan una forma muy limpia y concisa de trabajar con estructuras de control PHP mientras se mantienen familiares a sus contrapartes PHP.
Declaraciones If
Puedes construir declaraciones if
usando las directivas @if
, @elseif
, @else
y @endif
. Estas directivas funcionan de manera idéntica a sus contrapartes PHP:
@if (count($records) === 1)
I have one record!
@elseif (count($records) > 1)
I have multiple records!
@else
I don't have any records!
@endif
Para mayor comodidad, Blade también proporciona una directiva @unless
:
@unless (Auth::check())
You are not signed in.
@endunless
Además de las directivas condicionales ya discutidas, las directivas @isset
y @empty
pueden ser usadas como atajos convenientes para sus respectivas funciones PHP:
@isset($records)
// $records está definido y no es nulo...
@endisset
@empty($records)
// $records está "vacío"...
@endempty
Directivas de Autenticación
Las directivas @auth
y @guest
pueden usarse para determinar rápidamente si el usuario actual está autenticado o es un invitado:
@auth
// El usuario está autenticado...
@endauth
@guest
// El usuario no está autenticado...
@endguest
Si es necesario, puedes especificar el guard de autenticación que debe verificarse al usar las directivas @auth
y @guest
:
@auth('admin')
// El usuario está autenticado...
@endauth
@guest('admin')
// El usuario no está autenticado...
@endguest
Directivas de Entorno
Puedes verificar si la aplicación se está ejecutando en el entorno de producción usando la directiva @production
:
@production
// Contenido específico de producción...
@endproduction
O, puedes determinar si la aplicación se está ejecutando en un entorno específico usando la directiva @env
:
@env('staging')
// La aplicación se está ejecutando en "staging"...
@endenv
@env(['staging', 'production'])
// La aplicación se está ejecutando en "staging" o "production"...
@endenv
Directivas de Sección
Puedes determinar si una sección de herencia de plantilla tiene contenido usando la directiva @hasSection
:
@hasSection('navigation')
<div class="pull-right">
@yield('navigation')
</div>
<div class="clearfix"></div>
@endif
Puedes usar la directiva @sectionMissing
para determinar si una sección no tiene contenido:
@sectionMissing('navigation')
<div class="pull-right">
@include('default-navigation')
</div>
@endif
Directivas de Sesión
La directiva @session
puede usarse para determinar si existe un valor de sesión. Si el valor de sesión existe, el contenido de la plantilla dentro de las directivas @session
y @endsession
será evaluado. Dentro del contenido de la directiva @session
, puedes mostrar el valor de la sesión usando la variable $value
:
@session('status')
<div class="p-4 bg-green-100">
{{ $value }}
</div>
@endsession
Declaraciones Switch
Las declaraciones switch
pueden construirse usando las directivas @switch
, @case
, @break
, @default
y @endswitch
:
@switch($i)
@case(1)
First case...
@break
@case(2)
Second case...
@break
@default
Default case...
@endswitch
Bucles
Además de las declaraciones condicionales, Blade proporciona directivas simples para trabajar con las estructuras de bucle de PHP. Nuevamente, cada una de estas directivas funciona de manera idéntica a sus contrapartes PHP:
@for ($i = 0; $i < 10; $i++)
The current value is {{ $i }}
@endfor
@foreach ($users as $user)
<p>This is user {{ $user->id }}</p>
@endforeach
@forelse ($users as $user)
<li>{{ $user->name }}</li>
@empty
<p>No users</p>
@endforelse
@while (true)
<p>I'm looping forever.</p>
@endwhile
Mientras iteras a través de un bucle foreach
, puedes usar la variable $loop
para obtener información valiosa sobre el bucle, como si estás en la primera o última iteración del bucle.
Al usar bucles, también puedes omitir la iteración actual o finalizar el bucle usando las directivas @continue
y @break
:
@foreach ($users as $user)
@if ($user->type == 1)
@continue
@endif
<li>{{ $user->name }}</li>
@if ($user->number == 5)
@break
@endif
@endforeach
También puedes incluir la condición de continuación o ruptura dentro de la declaración de la directiva:
@foreach ($users as $user)
@continue($user->type == 1)
<li>{{ $user->name }}</li>
@break($user->number == 5)
@endforeach
La Variable Loop
Mientras iteras a través de un bucle foreach
, una variable $loop
estará disponible dentro de tu bucle. Esta variable proporciona acceso a algunos bits de información útiles, como el índice actual del bucle y si esta es la primera o última iteración del bucle:
@foreach ($users as $user)
@if ($loop->first)
This is the first iteration.
@endif
@if ($loop->last)
This is the last iteration.
@endif
<p>This is user {{ $user->id }}</p>
@endforeach
La Variable Loop
Si estás en un bucle anidado, puedes acceder a la variable $loop
del bucle padre a través de la propiedad parent
:
@foreach ($users as $user)
@foreach ($user->posts as $post)
@if ($loop->parent->first)
This is the first iteration of the parent loop.
@endif
@endforeach
@endforeach
La variable $loop
también contiene una variedad de otras propiedades útiles:
Propiedad | Descripción |
---|---|
$loop->index |
El índice de la iteración actual del bucle (comienza en 0). |
$loop->iteration |
La iteración actual del bucle (comienza en 1). |
$loop->remaining |
Las iteraciones restantes en el bucle. |
$loop->count |
El número total de elementos en el array que se está iterando. |
$loop->first |
Si esta es la primera iteración del bucle. |
$loop->last |
Si esta es la última iteración del bucle. |
$loop->even |
Si esta es una iteración par del bucle. |
$loop->odd |
Si esta es una iteración impar del bucle. |
$loop->depth |
El nivel de anidamiento del bucle actual. |
$loop->parent |
Cuando estás en un bucle anidado, la variable $loop del bucle padre. |
Clases y Estilos Condicionales
La directiva @class
compila condicionalmente una cadena de clases CSS. La directiva acepta una matriz de clases donde la clave de la matriz contiene la clase o clases que deseas agregar, mientras que el valor es una expresión booleana. Si el elemento de la matriz tiene una clave numérica, siempre se incluirá en la lista de clases renderizadas:
@php
$isActive = false;
$hasError = true;
@endphp
<span @class([
'p-4',
'font-bold' => $isActive,
'text-gray-500' => ! $isActive,
'bg-red' => $hasError,
])></span>
<span class="p-4 text-gray-500 bg-red"></span>
De igual manera, la directiva @style
puede usarse para agregar condicionalmente estilos CSS en línea a un elemento HTML:
@php
$isActive = true;
@endphp
<span @style([
'background-color: red',
'font-weight: bold' => $isActive,
])></span>
<span style="background-color: red; font-weight: bold;"></span>
Atributos Adicionales
Para mayor comodidad, puedes usar la directiva @checked
para indicar fácilmente si un input HTML de tipo checkbox está «checked». Esta directiva mostrará checked
si la condición proporcionada evalúa a true
:
<input type="checkbox"
name="active"
value="active"
@checked(old('active', $user->active)) />
De igual manera, la directiva @selected
puede usarse para indicar si una opción de un select debe estar «selected»:
<select name="version">
@foreach ($product->versions as $version)
<option value="{{ $version }}" @selected(old('version') == $version)>
{{ $version }}
</option>
@endforeach
</select>
Además, la directiva @disabled
puede usarse para indicar si un elemento dado debe estar «disabled»:
<button type="submit" @disabled($errors->isNotEmpty())>Submit</button>
Asimismo, la directiva @readonly
puede usarse para indicar si un elemento dado debe estar «readonly»:
<input type="email"
name="email"
value="email@laravel.com"
@readonly($user->isNotAdmin()) />
Además, la directiva @required
puede usarse para indicar si un elemento dado debe estar «required»:
<input type="text"
name="title"
value="title"
@required($user->isAdmin()) />
Incluyendo Subvistas
Aunque eres libre de usar la directiva @include
, los componentes Blade proporcionan una funcionalidad similar y ofrecen varios beneficios sobre la directiva @include
como la vinculación de datos y atributos.
La directiva @include
de Blade te permite incluir una vista Blade desde dentro de otra vista. Todas las variables que están disponibles para la vista padre estarán disponibles para la vista incluida:
<div>
@include('shared.errors')
<form>
<!-- Contenido del formulario -->
</form>
</div>
Aunque la vista incluida heredará todos los datos disponibles en la vista padre, también puedes pasar una matriz de datos adicionales que deben estar disponibles para la vista incluida:
@include('view.name', ['status' => 'complete'])
Si intentas @include
una vista que no existe, Laravel lanzará un error. Si deseas incluir una vista que puede o no estar presente, debes usar la directiva @includeIf
:
@includeIf('view.name', ['status' => 'complete'])
Si deseas @include
una vista si una expresión booleana dada evalúa a true
o false
, puedes usar las directivas @includeWhen
y @includeUnless
:
@includeWhen($boolean, 'view.name', ['status' => 'complete'])
@includeUnless($boolean, 'view.name', ['status' => 'complete'])
Para incluir la primera vista que exista de una matriz dada de vistas, puedes usar la directiva @includeFirst
:
@includeFirst(['custom.admin', 'admin'], ['status' => 'complete'])
Debes evitar usar las constantes __DIR__
y __FILE__
en tus vistas Blade, ya que se referirán a la ubicación de la vista compilada en caché.
Renderizando Vistas para Colecciones
Puedes combinar bucles e inclusiones en una sola línea con la directiva @each
de Blade:
@each('view.name', $jobs, 'job')
El primer argumento de la directiva @each
es la vista que se renderizará para cada elemento en el array o colección. El segundo argumento es el array o colección que deseas iterar, mientras que el tercer argumento es el nombre de la variable que se asignará a la iteración actual dentro de la vista. Por ejemplo, si estás iterando sobre un array de trabajos, normalmente querrás acceder a cada trabajo como una variable job
dentro de la vista. La clave del array para la iteración actual estará disponible como la variable key
dentro de la vista.
También puedes pasar un cuarto argumento a la directiva @each
. Este argumento determina la vista que se renderizará si el array dado está vacío.
@each('view.name', $jobs, 'job', 'view.empty')
Las vistas renderizadas a través de @each
no heredan las variables de la vista padre. Si la vista hija requiere estas variables, debes usar las directivas @foreach
y @include
en su lugar.
La Directiva @once
La directiva @once
te permite definir una porción de la plantilla que solo se evaluará una vez por ciclo de renderizado. Esto puede ser útil para insertar un fragmento de JavaScript en el encabezado de la página usando stacks. Por ejemplo, si estás renderizando un componente dado dentro de un bucle, puedes desear insertar el JavaScript en el encabezado solo la primera vez que se renderiza el componente:
@once
@push('scripts')
<script>
// Tu JavaScript personalizado...
</script>
@endpush
@endonce
Dado que la directiva @once
a menudo se usa en conjunto con las directivas @push
o @prepend
, las directivas @pushOnce
y @prependOnce
están disponibles para tu conveniencia:
@pushOnce('scripts')
<script>
// Tu JavaScript personalizado...
</script>
@endPushOnce
PHP Crudo
En algunas situaciones, es útil incrustar código PHP en tus vistas. Puedes usar la directiva @php
de Blade para ejecutar un bloque de PHP simple dentro de tu plantilla:
@php
$counter = 1;
@endphp
O, si solo necesitas usar PHP para importar una clase, puedes usar la directiva @use
:
@use('App\Models\Flight')
Se puede proporcionar un segundo argumento a la directiva @use
para aliasar la clase importada:
@use('App\Models\Flight', 'FlightModel')
Comentarios
Blade también te permite definir comentarios en tus vistas. Sin embargo, a diferencia de los comentarios HTML, los comentarios de Blade no se incluyen en el HTML devuelto por tu aplicación:
{{-- Este comentario no estará presente en el HTML renderizado --}}
Componentes
Los componentes y slots proporcionan beneficios similares a las secciones, layouts e inclusiones; sin embargo, algunos pueden encontrar el modelo mental de componentes y slots más fácil de entender. Hay dos enfoques para escribir componentes: componentes basados en clases y componentes anónimos.
Para crear un componente basado en clases, puedes usar el comando Artisan make:component
. Para ilustrar cómo usar componentes, crearemos un componente de alerta simple. El comando make:component
colocará el componente en el directorio app/View/Components
:
php artisan make:component Alert
El comando make:component
también creará una plantilla de vista para el componente. La vista se colocará en el directorio resources/views/components
. Al escribir componentes para tu propia aplicación, los componentes se descubren automáticamente dentro del directorio app/View/Components
y el directorio resources/views/components
, por lo que no se requiere un registro adicional de componentes.
También puedes crear componentes dentro de subdirectorios:
php artisan make:component Forms/Input
El comando anterior creará un componente Input
en el directorio app/View/Components/Forms
y la vista se colocará en el directorio resources/views/components/forms
.
Si deseas crear un componente anónimo (un componente con solo una plantilla Blade y sin clase), puedes usar la bandera --view
al invocar el comando make:component
:
php artisan make:component forms.input --view
El comando anterior creará un archivo Blade en resources/views/components/forms/input.blade.php
que puede ser renderizado como un componente a través de <x-forms.input />
.
Registrando Manualmente Componentes de Paquetes
Al escribir componentes para tu propia aplicación, los componentes se descubren automáticamente dentro del directorio app/View/Components
y el directorio resources/views/components
.
Sin embargo, si estás construyendo un paquete que utiliza componentes Blade, necesitarás registrar manualmente tu clase de componente y su alias de etiqueta HTML. Normalmente, debes registrar tus componentes en el método boot
del proveedor de servicios de tu paquete:
use Illuminate\Support\Facades\Blade;
/**
* Inicializar los servicios de tu paquete.
*/
public function boot(): void
{
Blade::component('package-alert', Alert::class);
}
Una vez que tu componente ha sido registrado, puede ser renderizado usando su alias de etiqueta:
<x-package-alert />
Alternativamente, puedes usar el método componentNamespace
para cargar automáticamente las clases de componentes por convención. Por ejemplo, un paquete Nightshade
podría tener componentes Calendar
y ColorPicker
que residen dentro del namespace Package\Views\Components
:
use Illuminate\Support\Facades\Blade;
/**
* Inicializar los servicios de tu paquete.
*/
public function boot(): void
{
Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}
Esto permitirá el uso de componentes de paquetes por su namespace de proveedor usando la sintaxis package-name::
:
<x-nightshade::calendar />
<x-nightshade::color-picker />
Blade detectará automáticamente la clase vinculada a este componente convirtiendo el nombre del componente a PascalCase. Los subdirectorios también son compatibles usando la notación de «punto».
Renderizando Componentes
Para mostrar un componente, puedes usar una etiqueta de componente Blade dentro de una de tus plantillas Blade. Las etiquetas de componente Blade comienzan con la cadena x-
seguida del nombre en kebab case de la clase del componente:
<x-alert />
<x-user-profile />
Si la clase del componente está anidada más profundamente dentro del directorio app/View/Components
, puedes usar el carácter .
para indicar la anidación del directorio. Por ejemplo, si asumimos que un componente está ubicado en app/View/Components/Inputs/Button.php
, podemos renderizarlo así:
<x-inputs.button />
Si deseas renderizar condicionalmente tu componente, puedes definir un método shouldRender
en tu clase de componente. Si el método shouldRender
devuelve false
, el componente no se renderizará:
use Illuminate\Support\Str;
/**
* Si el componente debe ser renderizado
*/
public function shouldRender(): bool
{
return Str::length($this->message) > 0;
}
Pasando Datos a Componentes
Puedes pasar datos a los componentes Blade usando atributos HTML. Los valores primitivos codificados pueden pasarse al componente usando cadenas de atributos HTML simples. Las expresiones y variables PHP deben pasarse al componente a través de atributos que usen el prefijo :
:
<x-alert type="error" :message="$message" />
Debes definir todos los atributos de datos del componente en su constructor de clase. Todas las propiedades públicas de un componente estarán automáticamente disponibles para la vista del componente. No es necesario pasar los datos a la vista desde el método render
del componente:
<?php
namespace App\View\Components;
use Illuminate\View\Component;
use Illuminate\View\View;
class Alert extends Component
{
/**
* Crear una instancia del componente.
*/
public function __construct(
public string $type,
public string $message,
) {}
/**
* Obtener la vista/contenido que representa el componente.
*/
public function render(): View
{
return view('components.alert');
}
}
Cuando tu componente se renderiza, puedes mostrar el contenido de las variables públicas de tu componente haciendo eco de las variables por nombre:
<div class="alert alert-{{ $type }}">
{{ $message }}
</div>
Convenciones de Nombres
Los argumentos del constructor del componente deben especificarse usando camelCase, mientras que se debe usar kebab-case al referenciar los nombres de los argumentos en tus atributos HTML. Por ejemplo, dado el siguiente constructor de componente:
/**
* Crear una instancia del componente.
*/
public function __construct(
public string $alertType,
) {}
El argumento $alertType
puede proporcionarse al componente de la siguiente manera:
<x-alert alert-type="danger" />
Sintaxis de Atributos Cortos
Al pasar atributos a componentes, también puedes usar una sintaxis de «atributo corto». Esto es a menudo conveniente ya que los nombres de los atributos frecuentemente coinciden con los nombres de las variables a las que corresponden:
{{-- Sintaxis de atributo corto... --}}
<x-profile :$userId :$name />
{{-- Es equivalente a... --}}
<x-profile :user-id="$userId" :name="$name" />
Escapando la Renderización de Atributos
Dado que algunos frameworks JavaScript como Alpine.js también usan atributos con prefijo de dos puntos, puedes usar un prefijo de doble dos puntos ::
para informar a Blade que el atributo no es una expresión PHP. Por ejemplo, dado el siguiente componente:
<x-button ::class="{ danger: isDeleting }">
Submit
</x-button>
El siguiente HTML será renderizado por Blade:
<button :class="{ danger: isDeleting }">
Submit
</button>
Métodos de Componentes
Además de las variables públicas disponibles para tu plantilla de componente, cualquier método público en el componente puede ser invocado. Por ejemplo, imagina un componente que tiene un método isSelected
:
/**
* Determinar si la opción dada es la opción actualmente seleccionada.
*/
public function isSelected(string $option): bool
{
return $option === $this->selected;
}
Puedes ejecutar este método desde tu plantilla de componente invocando la variable que coincide con el nombre del método:
<option {{ $isSelected($value) ? 'selected' : '' }} value="{{ $value }}">
{{ $label }}
</option>
Accediendo a Atributos y Slots Dentro de Clases de Componentes
Los componentes Blade también te permiten acceder al nombre del componente, atributos y slot dentro del método render
de la clase. Sin embargo, para acceder a estos datos, debes devolver un closure desde el método render
de tu componente:
use Closure;
/**
* Obtener la vista/contenido que representa el componente.
*/
public function render(): Closure
{
return function () {
return '<div {{ $attributes }}>Contenido del componente</div>';
};
}
El closure devuelto por el método render
de tu componente también puede recibir un array $data
como su único argumento. Este array contendrá varios elementos que proporcionan información sobre el componente:
return function (array $data) {
// $data['componentName'];
// $data['attributes'];
// $data['slot'];
return '<div {{ $attributes }}>Contenido del componente</div>';
}
Los elementos en el array $data
nunca deben ser incrustados directamente en la cadena Blade devuelta por tu método render
, ya que hacerlo podría permitir la ejecución remota de código a través de contenido de atributos malicioso.
El componentName
es igual al nombre usado en la etiqueta HTML después del prefijo x-
. Así que el componentName
de <x-alert />
será alert
. El elemento attributes
contendrá todos los atributos que estaban presentes en la etiqueta HTML. El elemento slot
es una instancia de Illuminate\Support\HtmlString
con el contenido del slot del componente.
El closure debe devolver una cadena. Si la cadena devuelta corresponde a una vista existente, esa vista será renderizada; de lo contrario, la cadena devuelta será evaluada como una vista Blade en línea.
Dependencias Adicionales
Si tu componente requiere dependencias del contenedor de servicios de Laravel, puedes listarlas antes de cualquiera de los atributos de datos del componente y serán inyectadas automáticamente por el contenedor:
use App\Services\AlertCreator;
/**
* Crear una instancia del componente.
*/
public function __construct(
public AlertCreator $creator,
public string $type,
public string $message,
) {}
Ocultando Atributos/Métodos
Si deseas evitar que algunos métodos o propiedades públicas sean expuestos como variables a tu plantilla de componente, puedes agregarlos a una propiedad $except
en tu componente:
<?php
namespace App\View\Components;
use Illuminate\View\Component;
class Alert extends Component
{
/**
* Las propiedades/métodos que no deben ser expuestos a la plantilla del componente.
*
* @var array
*/
protected $except = ['type'];
/**
* Crear una instancia del componente.
*/
public function __construct(
public string $type,
) {}
}
Atributos de Componentes
Ya hemos examinado cómo pasar atributos de datos a un componente; sin embargo, a veces puedes necesitar especificar atributos HTML adicionales, como class
, que no son parte de los datos necesarios para que un componente funcione. Normalmente, querrás pasar estos atributos adicionales al elemento raíz de la plantilla del componente. Por ejemplo, imagina que queremos renderizar un componente de alerta así:
<x-alert type="error" :message="$message" class="mt-4" />
Todos los atributos que no son parte del constructor del componente se agregarán automáticamente a la «bolsa de atributos» del componente. Esta bolsa de atributos está automáticamente disponible para el componente a través de la variable $attributes
. Todos los atributos pueden ser renderizados dentro del componente haciendo eco de esta variable:
<div {{ $attributes }}>
<!-- Contenido del componente -->
</div>
Usar directivas como @env
dentro de etiquetas de componentes no es compatible en este momento. Por ejemplo, <x-alert :live="@env('production')" />
no será compilado.
Atributos Predeterminados / Combinados
A veces puedes necesitar especificar valores predeterminados para los atributos o combinar valores adicionales en algunos de los atributos del componente. Para lograr esto, puedes usar el método merge
de la bolsa de atributos. Este método es particularmente útil para definir un conjunto de clases CSS predeterminadas que siempre deben aplicarse a un componente:
<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
{{ $message }}
</div>
Si asumimos que este componente se utiliza así:
<x-alert type="error" :message="$message" class="mb-4" />
El HTML final renderizado del componente aparecerá de la siguiente manera:
<div class="alert alert-error mb-4">
<!-- Contenido de la variable $message -->
</div>
Combinación Condicional de Clases
A veces puedes desear combinar clases si una condición dada es verdadera. Puedes lograr esto a través del método class
, que acepta una matriz de clases donde la clave de la matriz contiene la clase o clases que deseas agregar, mientras que el valor es una expresión booleana. Si el elemento de la matriz tiene una clave numérica, siempre se incluirá en la lista de clases renderizadas:
<div {{ $attributes->class(['p-4', 'bg-red' => $hasError]) }}>
{{ $message }}
</div>
Si necesitas combinar otros atributos en tu componente, puedes encadenar el método merge
al método class
:
<button {{ $attributes->class(['p-4'])->merge(['type' => 'button']) }}>
{{ $slot }}
</button>
Si necesitas compilar condicionalmente clases en otros elementos HTML que no deberían recibir atributos combinados, puedes usar la directiva @class
.
Combinación de Atributos No-Clase
Al combinar atributos que no son atributos de clase, los valores proporcionados al método merge
se considerarán los valores «predeterminados» del atributo. Sin embargo, a diferencia del atributo de clase, estos atributos no se combinarán con los valores de atributos inyectados. En su lugar, serán sobrescritos. Por ejemplo, la implementación de un componente de botón puede verse así:
<button {{ $attributes->merge(['type' => 'button']) }}>
{{ $slot }}
</button>
Para renderizar el componente de botón con un tipo personalizado, puede especificarse al consumir el componente. Si no se especifica ningún tipo, se usará el tipo de botón:
<x-button type="submit">
Submit
</x-button>
El HTML renderizado del componente de botón en este ejemplo sería:
<button type="submit">
Submit
</button>
Si deseas que un atributo que no sea clase tenga su valor predeterminado y los valores inyectados unidos, puedes usar el método prepends
. En este ejemplo, el atributo data-controller
siempre comenzará con profile-controller
y cualquier valor adicional de data-controller
inyectado se colocará después de este valor predeterminado:
<div {{ $attributes->merge(['data-controller' => $attributes->prepends('profile-controller')]) }}>
{{ $slot }}
</div>
Recuperando y Filtrando Atributos
Puedes filtrar atributos usando el método filter
. Este método acepta un closure que debe devolver true
si deseas retener el atributo en la bolsa de atributos:
{{ $attributes->filter(fn (string $value, string $key) => $key == 'foo') }}
Para mayor comodidad, puedes usar el método whereStartsWith
para recuperar todos los atributos cuyos nombres comienzan con una cadena dada:
{{ $attributes->whereStartsWith('wire:model') }}
Por el contrario, el método whereDoesntStartWith
puede usarse para excluir todos los atributos cuyos nombres comienzan con una cadena dada:
{{ $attributes->whereDoesntStartWith('wire:model') }}
Usando el método first
, puedes renderizar el primer atributo en una bolsa de atributos dada:
{{ $attributes->whereStartsWith('wire:model')->first() }}
Si deseas verificar si un atributo está presente en el componente, puedes usar el método has
. Este método acepta el nombre del atributo como su único argumento y devuelve un booleano que indica si el atributo está presente o no:
@if ($attributes->has('class'))
<div>El atributo class está presente</div>
@endif
Si se pasa un array al método has
, el método determinará si todos los atributos dados están presentes en el componente:
@if ($attributes->has(['name', 'class']))
<div>Todos los atributos están presentes</div>
@endif
El método hasAny
puede usarse para determinar si alguno de los atributos dados está presente en el componente:
@if ($attributes->hasAny(['href', ':href', 'v-bind:href']))
<div>Uno de los atributos está presente</div>
@endif
Puedes recuperar el valor de un atributo específico usando el método get
:
{{ $attributes->get('class') }}
Palabras Reservadas
Por defecto, algunas palabras clave están reservadas para el uso interno de Blade para renderizar componentes. Las siguientes palabras clave no pueden definirse como propiedades públicas o nombres de métodos dentro de tus componentes:
- data
- render
- resolveView
- shouldRender
- view
- withAttributes
- withName
Slots
A menudo necesitarás pasar contenido adicional a tu componente a través de «slots». Los slots de componentes se renderizan haciendo eco de la variable $slot
. Para explorar este concepto, imaginemos que un componente de alerta tiene el siguiente marcado:
<!-- /resources/views/components/alert.blade.php -->
<div class="alert alert-danger">
{{ $slot }}
</div>
Puedes pasar contenido al slot inyectando contenido en el componente:
<x-alert>
<strong>Whoops!</strong> Something went wrong!
</x-alert>
A veces un componente puede necesitar renderizar múltiples slots diferentes en diferentes ubicaciones dentro del componente. Vamos a modificar nuestro componente de alerta para permitir la inyección de un slot «title»:
<!-- /resources/views/components/alert.blade.php -->
<span class="alert-title">{{ $title }}</span>
<div class="alert alert-danger">
{{ $slot }}
</div>
Puedes definir el contenido del slot nombrado usando la etiqueta x-slot
. Cualquier contenido que no esté dentro de una etiqueta x-slot
explícita se pasará al componente en la variable $slot
:
<x-alert>
<x-slot:title>
Server Error
</x-slot>
<strong>Whoops!</strong> Something went wrong!
</x-alert>
Puedes invocar el método isEmpty
de un slot para determinar si el slot contiene contenido:
<span class="alert-title">{{ $title }}</span>
<div class="alert alert-danger">
@if ($slot->isEmpty())
This is default content if the slot is empty.
@else
{{ $slot }}
@endif
</div>
Además, el método hasActualContent
puede usarse para determinar si el slot contiene algún contenido «real» que no sea un comentario HTML:
@if ($slot->hasActualContent())
The scope has non-comment content.
@endif
Slots con Alcance
Si has usado un framework JavaScript como Vue, puedes estar familiarizado con los «slots con alcance», que te permiten acceder a datos o métodos del componente dentro de tu slot. Puedes lograr un comportamiento similar en Laravel definiendo métodos o propiedades públicas en tu componente y accediendo al componente dentro de tu slot a través de la variable $component
. En este ejemplo, asumiremos que el componente x-alert
tiene un método público formatAlert
definido en su clase de componente:
<x-alert>
<x-slot:title>
{{ $component->formatAlert('Server Error') }}
</x-slot>
<strong>Whoops!</strong> Something went wrong!
</x-alert>
Atributos de Slots
Al igual que los componentes Blade, puedes asignar atributos adicionales a los slots, como nombres de clases CSS:
<x-card class="shadow-sm">
<x-slot:heading class="font-bold">
Heading
</x-slot>
Content
<x-slot:footer class="text-sm">
Footer
</x-slot>
</x-card>
Para interactuar con los atributos de los slots, puedes acceder a la propiedad attributes
de la variable del slot. Para obtener más información sobre cómo interactuar con los atributos, consulta la documentación sobre atributos de componentes:
@props([
'heading',
'footer',
])
<div {{ $attributes->class(['border']) }}>
<h1 {{ $heading->attributes->class(['text-lg']) }}>
{{ $heading }}
</h1>
{{ $slot }}
<footer {{ $footer->attributes->class(['text-gray-700']) }}>
{{ $footer }}
</footer>
</div>
Vistas de Componentes en Línea
Para componentes muy pequeños, puede resultar engorroso gestionar tanto la clase del componente como la plantilla de vista del componente. Por esta razón, puedes devolver el marcado del componente directamente desde el método render
:
/**
* Obtener la vista/contenido que representa el componente.
*/
public function render(): string
{
return <<<'blade'
<div class="alert alert-danger">
{{ $slot }}
</div>
blade;
}
Generando Componentes de Vista en Línea
Para crear un componente que renderice una vista en línea, puedes usar la opción inline
al ejecutar el comando make:component
:
php artisan make:component Alert --inline
Componentes Dinámicos
A veces puedes necesitar renderizar un componente pero no saber qué componente debe renderizarse hasta el tiempo de ejecución. En esta situación, puedes usar el componente dynamic-component
incorporado de Laravel para renderizar el componente basado en un valor o variable en tiempo de ejecución:
// $componentName = "secondary-button";
<x-dynamic-component :component="$componentName" class="mt-4" />
Registrando Componentes Manualmente
La siguiente documentación sobre el registro manual de componentes es principalmente aplicable a aquellos que están escribiendo paquetes de Laravel que incluyen componentes de vista. Si no estás escribiendo un paquete, esta parte de la documentación de componentes puede no ser relevante para ti.
Al escribir componentes para tu propia aplicación, los componentes se descubren automáticamente dentro del directorio app/View/Components
y el directorio resources/views/components
.
Sin embargo, si estás construyendo un paquete que utiliza componentes Blade o colocando componentes en directorios no convencionales, necesitarás registrar manualmente tu clase de componente y su alias de etiqueta HTML para que Laravel sepa dónde encontrar el componente. Normalmente, debes registrar tus componentes en el método boot
del proveedor de servicios de tu paquete:
use Illuminate\Support\Facades\Blade;
use VendorPackage\View\Components\AlertComponent;
/**
* Inicializar los servicios de tu paquete.
*/
public function boot(): void
{
Blade::component('package-alert', AlertComponent::class);
}
Una vez que tu componente ha sido registrado, puede ser renderizado usando su alias de etiqueta:
<x-package-alert />
Carga Automática de Componentes de Paquetes
Alternativamente, puedes usar el método componentNamespace
para cargar automáticamente las clases de componentes por convención. Por ejemplo, un paquete Nightshade
podría tener componentes Calendar
y ColorPicker
que residen dentro del namespace Package\Views\Components
:
use Illuminate\Support\Facades\Blade;
/**
* Inicializar los servicios de tu paquete.
*/
public function boot(): void
{
Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}
Esto permitirá el uso de componentes de paquetes por su namespace de proveedor usando la sintaxis package-name::
:
<x-nightshade::calendar />
<x-nightshade::color-picker />
Blade detectará automáticamente la clase vinculada a este componente convirtiendo el nombre del componente a PascalCase. Los subdirectorios también son compatibles usando la notación de «punto».
Componentes Anónimos
Similar a los componentes en línea, los componentes anónimos proporcionan un mecanismo para gestionar un componente a través de un solo archivo. Sin embargo, los componentes anónimos utilizan un solo archivo de vista y no tienen una clase asociada. Para definir un componente anónimo, solo necesitas colocar una plantilla Blade dentro de tu directorio resources/views/components
. Por ejemplo, asumiendo que has definido un componente en resources/views/components/alert.blade.php
, puedes renderizarlo simplemente así:
<x-alert />
Puedes usar el carácter .
para indicar si un componente está anidado más profundamente dentro del directorio de componentes. Por ejemplo, asumiendo que el componente está definido en resources/views/components/inputs/button.blade.php
, puedes renderizarlo así:
<x-inputs.button />
Componentes de Índice Anónimos
A veces, cuando un componente está compuesto por muchas plantillas Blade, puedes desear agrupar las plantillas del componente dado dentro de un solo directorio. Por ejemplo, imagina un componente «accordion» con la siguiente estructura de directorios:
/resources/views/components/accordion.blade.php
/resources/views/components/accordion/item.blade.php
Esta estructura de directorios te permite renderizar el componente accordion y su item así:
<x-accordion>
<x-accordion.item>
...
</x-accordion.item>
</x-accordion>
Sin embargo, para renderizar el componente accordion a través de <x-accordion>
, nos vimos obligados a colocar la plantilla del componente «índice» accordion en el directorio resources/views/components
en lugar de anidarlo dentro del directorio accordion con las otras plantillas relacionadas con accordion.
Afortunadamente, Blade te permite colocar un archivo index.blade.php
dentro del directorio de plantillas del componente. Cuando existe una plantilla index.blade.php
para el componente, se renderizará como el nodo «raíz» del componente. Así que, podemos seguir usando la misma sintaxis Blade dada en el ejemplo anterior; sin embargo, ajustaremos nuestra estructura de directorios así:
/resources/views/components/accordion/index.blade.php
/resources/views/components/accordion/item.blade.php
Propiedades de Datos / Atributos
Dado que los componentes anónimos no tienen ninguna clase asociada, puedes preguntarte cómo diferenciar qué datos deben pasarse al componente como variables y qué atributos deben colocarse en la bolsa de atributos del componente.
Puedes especificar qué atributos deben considerarse variables de datos usando la directiva @props
en la parte superior de la plantilla Blade de tu componente. Todos los demás atributos en el componente estarán disponibles a través de la bolsa de atributos del componente. Si deseas dar un valor predeterminado a una variable de datos, puedes especificar el nombre de la variable como la clave del array y el valor predeterminado como el valor del array:
<!-- /resources/views/components/alert.blade.php -->
@props(['type' => 'info', 'message'])
<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
{{ $message }}
</div>
Dada la definición del componente anterior, podemos renderizar el componente así:
<x-alert type="error" :message="$message" class="mb-4" />
Accediendo a Datos del Padre
A veces puedes querer acceder a datos de un componente padre dentro de un componente hijo. En estos casos, puedes usar la directiva @aware
. Por ejemplo, imagina que estamos construyendo un componente de menú complejo que consiste en un <x-menu>
padre y un <x-menu.item>
hijo:
<x-menu color="purple">
<x-menu.item>...</x-menu.item>
<x-menu.item>...</x-menu.item>
</x-menu>
El componente <x-menu>
puede tener una implementación como la siguiente:
<!-- /resources/views/components/menu/index.blade.php -->
@props(['color' => 'gray'])
<ul {{ $attributes->merge(['class' => 'bg-'.$color.'-200']) }}>
{{ $slot }}
</ul>
Debido a que el prop color
solo se pasó al padre (<x-menu>
), no estará disponible dentro de <x-menu.item>
. Sin embargo, si usamos la directiva @aware
, podemos hacerlo disponible dentro de <x-menu.item>
también:
<!-- /resources/views/components/menu/item.blade.php -->
@aware(['color' => 'gray'])
<li {{ $attributes->merge(['class' => 'text-'.$color.'-800']) }}>
{{ $slot }}
</li>
La directiva @aware
no puede acceder a datos del padre que no se pasen explícitamente al componente padre a través de atributos HTML. Los valores predeterminados de @props
que no se pasen explícitamente al componente padre no pueden ser accedidos por la directiva @aware
.
Rutas de Componentes Anónimos
Como se discutió anteriormente, los componentes anónimos se definen típicamente colocando una plantilla Blade dentro de tu directorio resources/views/components
. Sin embargo, ocasionalmente puedes querer registrar otras rutas de componentes anónimos con Laravel además de la ruta predeterminada.
El método anonymousComponentPath
acepta la «ruta» a la ubicación del componente anónimo como su primer argumento y un «namespace» opcional en el que los componentes deben colocarse como su segundo argumento. Normalmente, este método debe llamarse desde el método boot
de uno de los proveedores de servicios de tu aplicación:
/**
* Inicializar cualquier servicio de la aplicación.
*/
public function boot(): void
{
Blade::anonymousComponentPath(__DIR__.'/../components');
}
Cuando las rutas de componentes se registran sin un prefijo especificado como en el ejemplo anterior, pueden renderizarse en tus componentes Blade sin un prefijo correspondiente también. Por ejemplo, si existe un componente panel.blade.php
en la ruta registrada anteriormente, puede renderizarse así:
<x-panel />
Los «namespaces» de prefijo pueden proporcionarse como el segundo argumento al método anonymousComponentPath
:
Blade::anonymousComponentPath(__DIR__.'/../components', 'dashboard');
Cuando se proporciona un prefijo, los componentes dentro de ese «namespace» pueden renderizarse prefijando el namespace del componente al nombre del componente cuando se renderiza:
<x-dashboard::panel />
Construyendo Layouts
Layouts Usando Componentes
La mayoría de las aplicaciones web mantienen el mismo layout general en varias páginas. Sería increíblemente engorroso y difícil de mantener nuestra aplicación si tuviéramos que repetir todo el HTML del layout en cada vista que creamos. Afortunadamente, es conveniente definir este layout como un solo componente Blade y luego usarlo en toda nuestra aplicación.
Definiendo el Componente de Layout
Por ejemplo, imagina que estamos construyendo una aplicación de lista de «tareas». Podríamos definir un componente de layout que se vea así:
<!-- resources/views/components/layout.blade.php -->
<html>
<head>
<title>{{ $title ?? 'Todo Manager' }}</title>
</head>
<body>
<h1>Todos</h1>
<hr/>
{{ $slot }}
</body>
</html>
Aplicando el Componente de Layout
Una vez que el componente de layout ha sido definido, podemos crear una vista Blade que utilice el componente. En este ejemplo, definiremos una vista simple que muestra nuestra lista de tareas:
<!-- resources/views/tasks.blade.php -->
<x-layout>
@foreach ($tasks as $task)
<div>{{ $task }}</div>
@endforeach
</x-layout>
Recuerda, el contenido que se inyecta en un componente se suministrará a la variable $slot
predeterminada dentro de nuestro componente de layout. Como habrás notado, nuestro layout también respeta un slot $title
si se proporciona uno; de lo contrario, se muestra un título predeterminado. Podemos inyectar un título personalizado desde nuestra vista de lista de tareas usando la sintaxis estándar de slots discutida en la documentación de componentes:
<!-- resources/views/tasks.blade.php -->
<x-layout>
<x-slot:title>
Custom Title
</x-slot>
@foreach ($tasks as $task)
<div>{{ $task }}</div>
@endforeach
</x-layout>
Ahora que hemos definido nuestro layout y vistas de lista de tareas, solo necesitamos devolver la vista de tareas desde una ruta:
use App\Models\Task;
Route::get('/tasks', function () {
return view('tasks', ['tasks' => Task::all()]);
});
Layouts Usando Herencia de Plantillas
Definiendo un Layout
Los layouts también pueden crearse a través de la «herencia de plantillas». Esta era la forma principal de construir aplicaciones antes de la introducción de los componentes.
Para comenzar, echemos un vistazo a un ejemplo simple. Primero, examinaremos un layout de página. Dado que la mayoría de las aplicaciones web mantienen el mismo layout general en varias páginas, es conveniente definir este layout como una sola vista Blade:
<!-- resources/views/layouts/app.blade.php -->
<html>
<head>
<title>App Name - @yield('title')</title>
</head>
<body>
@section('sidebar')
This is the master sidebar.
@show
<div class="container">
@yield('content')
</div>
</body>
</html>
Como puedes ver, este archivo contiene marcado HTML típico. Sin embargo, toma nota de las directivas @section
y @yield
. La directiva @section
, como su nombre lo indica, define una sección de contenido, mientras que la directiva @yield
se usa para mostrar el contenido de una sección dada.
Ahora que hemos definido un layout para nuestra aplicación, definamos una página hija que herede el layout.
Extendiendo un Layout
Al definir una vista hija, usa la directiva Blade @extends
para especificar qué layout debe «heredar» la vista hija. Las vistas que extienden un layout Blade pueden inyectar contenido en las secciones del layout usando directivas @section
. Recuerda, como se vio en el ejemplo anterior, el contenido de estas secciones se mostrará en el layout usando @yield
:
<!-- resources/views/child.blade.php -->
@extends('layouts.app')
@section('title', 'Page Title')
@section('sidebar')
@parent
<p>This is appended to the master sidebar.</p>
@endsection
@section('content')
<p>This is my body content.</p>
@endsection
En este ejemplo, la sección de la barra lateral está utilizando la directiva @parent
para agregar (en lugar de sobrescribir) contenido a la barra lateral del layout. La directiva @parent
será reemplazada por el contenido del layout cuando la vista sea renderizada.
Contrario al ejemplo anterior, esta sección de la barra lateral termina con @endsection
en lugar de @show
. La directiva @endsection
solo definirá una sección mientras que @show
definirá e inmediatamente mostrará la sección.
La directiva @yield
también acepta un valor predeterminado como su segundo parámetro. Este valor se renderizará si la sección que se está mostrando no está definida:
@yield('content', 'Default content')
Formularios
Campo CSRF
Cada vez que defines un formulario HTML en tu aplicación, debes incluir un campo de token CSRF oculto en el formulario para que el middleware de protección CSRF pueda validar la solicitud. Puedes usar la directiva Blade @csrf
para generar el campo de token:
<form method="POST" action="/profile">
@csrf
...
</form>
Campo de Método
Dado que los formularios HTML no pueden hacer solicitudes PUT, PATCH o DELETE, necesitarás agregar un campo _method
oculto para simular estos verbos HTTP. La directiva Blade @method
puede crear este campo por ti:
<form action="/foo/bar" method="POST">
@method('PUT')
...
</form>
Errores de Validación
La directiva @error
puede usarse para verificar rápidamente si existen mensajes de error de validación para un atributo dado. Dentro de una directiva @error
, puedes hacer eco de la variable $message
para mostrar el mensaje de error:
<!-- /resources/views/post/create.blade.php -->
<label for="title">Post Title</label>
<input id="title"
type="text"
class="@error('title') is-invalid @enderror">
@error('title')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
Dado que la directiva @error
se compila en una declaración «if», puedes usar la directiva @else
para renderizar contenido cuando no hay un error para un atributo:
<!-- /resources/views/auth.blade.php -->
<label for="email">Email address</label>
<input id="email"
type="email"
class="@error('email') is-invalid @else is-valid @enderror">
Puedes pasar el nombre de una bolsa de errores específica como segundo parámetro a la directiva @error
para recuperar mensajes de error de validación en páginas que contienen múltiples formularios:
<!-- /resources/views/auth.blade.php -->
<label for="email">Email address</label>
<input id="email"
type="email"
class="@error('email', 'login') is-invalid @enderror">
@error('email', 'login')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
Stacks
Blade te permite agregar contenido a stacks nombrados que pueden renderizarse en otro lugar en otra vista o layout. Esto puede ser particularmente útil para especificar cualquier biblioteca de JavaScript requerida por tus vistas hijas:
@push('scripts')
<script src="/example.js"></script>
@endpush
Si deseas @push
contenido si una expresión booleana dada evalúa a true
, puedes usar la directiva @pushIf
:
@pushIf($shouldPush, 'scripts')
<script src="/example.js"></script>
@endPushIf
Puedes agregar contenido a un stack tantas veces como sea necesario. Para renderizar el contenido completo del stack, pasa el nombre del stack a la directiva @stack
:
<head>
<!-- Contenido del Head -->
@stack('scripts')
</head>
Si deseas agregar contenido al principio de un stack, debes usar la directiva @prepend
:
@push('scripts')
This will be second...
@endpush
// Later...
@prepend('scripts')
This will be first...
@endprepend
Inyección de Servicios
La directiva @inject
puede usarse para recuperar un servicio del contenedor de servicios de Laravel. El primer argumento pasado a @inject
es el nombre de la variable en la que se colocará el servicio, mientras que el segundo argumento es el nombre de la clase o interfaz del servicio que deseas resolver:
@inject('metrics', 'App\Services\MetricsService')
<div>
Monthly Revenue: {{ $metrics->monthlyRevenue() }}.
</div>
Renderizando Plantillas Blade en Línea
A veces puedes necesitar transformar una cadena de plantilla Blade en HTML válido. Puedes lograr esto usando el método render
proporcionado por la fachada Blade. El método render
acepta la cadena de plantilla Blade y un array opcional de datos para proporcionar a la plantilla:
use Illuminate\Support\Facades\Blade;
return Blade::render('Hello, {{ $name }}', ['name' => 'Julian Bashir']);
Laravel renderiza plantillas Blade en línea escribiéndolas en el directorio storage/framework/views
. Si deseas que Laravel elimine estos archivos temporales después de renderizar la plantilla Blade, puedes proporcionar el argumento deleteCachedView
al método:
return Blade::render(
'Hello, {{ $name }}',
['name' => 'Julian Bashir'],
deleteCachedView: true
);
Renderizando Fragmentos Blade
Al usar frameworks frontend como Turbo y htmx, puedes necesitar ocasionalmente devolver solo una parte de una plantilla Blade dentro de tu respuesta HTTP. Los «fragmentos» Blade te permiten hacer precisamente eso. Para comenzar, coloca una parte de tu plantilla Blade dentro de las directivas @fragment
y @endfragment
:
@fragment('user-list')
<ul>
@foreach ($users as $user)
<li>{{ $user->name }}</li>
@endforeach
</ul>
@endfragment
Luego, al renderizar la vista que utiliza esta plantilla, puedes invocar el método fragment
para especificar que solo el fragmento especificado debe incluirse en la respuesta HTTP saliente:
return view('dashboard', ['users' => $users])->fragment('user-list');
El método fragmentIf
te permite devolver condicionalmente un fragmento de una vista basado en una condición dada. De lo contrario, se devolverá toda la vista:
return view('dashboard', ['users' => $users])
->fragmentIf($request->hasHeader('HX-Request'), 'user-list');
Los métodos fragments
y fragmentsIf
te permiten devolver múltiples fragmentos de vista en la respuesta. Los fragmentos se concatenarán juntos:
view('dashboard', ['users' => $users])
->fragments(['user-list', 'comment-list']);
view('dashboard', ['users' => $users])
->fragmentsIf(
$request->hasHeader('HX-Request'),
['user-list', 'comment-list']
);
Extendiendo Blade
Blade te permite definir tus propias directivas personalizadas usando el método directive
. Cuando el compilador Blade encuentra la directiva personalizada, llamará al callback proporcionado con la expresión que contiene la directiva.
El siguiente ejemplo crea una directiva @datetime($var)
que formatea una variable $var
, que debería ser una instancia de DateTime
:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Registrar cualquier servicio de la aplicación.
*/
public function register(): void
{
// ...
}
/**
* Inicializar cualquier servicio de la aplicación.
*/
public function boot(): void
{
Blade::directive('datetime', function (string $expression) {
return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
});
}
}
Como puedes ver, encadenaremos el método format
a cualquier expresión que se pase a la directiva. Así que, en este ejemplo, el PHP final generado por esta directiva será:
<?php echo ($var)->format('m/d/Y H:i'); ?>
Después de actualizar la lógica de una directiva Blade, necesitarás eliminar todas las vistas Blade en caché. Las vistas Blade en caché pueden eliminarse usando el comando Artisan view:clear
.
Manejadores de Echo Personalizados
Si intentas «hacer eco» de un objeto usando Blade, se invocará el método __toString
del objeto. El método __toString
es uno de los «métodos mágicos» incorporados de PHP. Sin embargo, a veces puede que no tengas control sobre el método __toString
de una clase dada, como cuando la clase con la que estás interactuando pertenece a una biblioteca de terceros.
En estos casos, Blade te permite registrar un manejador de echo personalizado para ese tipo particular de objeto. Para lograr esto, debes invocar el método stringable
de Blade. El método stringable
acepta un closure. Este closure debe tener una pista de tipo del tipo de objeto que es responsable de renderizar. Típicamente, el método stringable
debe invocarse dentro del método boot
de la clase AppServiceProvider
de tu aplicación:
use Illuminate\Support\Facades\Blade;
use Money\Money;
/**
* Inicializar cualquier servicio de la aplicación.
*/
public function boot(): void
{
Blade::stringable(function (Money $money) {
return $money->formatTo('en_GB');
});
}
Una vez que tu manejador de echo personalizado ha sido definido, puedes simplemente hacer eco del objeto en tu plantilla Blade:
Cost: {{ $money }}
Declaraciones If Personalizadas
Programar una directiva personalizada a veces es más complejo de lo necesario al definir declaraciones condicionales simples y personalizadas. Por esa razón, Blade proporciona un método Blade::if
que te permite definir rápidamente directivas condicionales personalizadas usando closures. Por ejemplo, definamos una condición personalizada que verifique el «disco» predeterminado configurado para la aplicación. Podemos hacer esto en el método boot
de nuestro AppServiceProvider
:
use Illuminate\Support\Facades\Blade;
/**
* Inicializar cualquier servicio de la aplicación.
*/
public function boot(): void
{
Blade::if('disk', function (string $value) {
return config('filesystems.default') === $value;
});
}
Una vez que la condición personalizada ha sido definida, puedes usarla dentro de tus plantillas:
@disk('local')
<!-- La aplicación está usando el disco local... -->
@elsedisk('s3')
<!-- La aplicación está usando el disco s3... -->
@else
<!-- La aplicación está usando algún otro disco... -->
@enddisk
@unlessdisk('local')
<!-- La aplicación no está usando el disco local... -->
@enddisk