git |
---|
724c31ccd3edce6b6dfe5e0dd2a594a47217f078 |
Blade – это простой, но мощный движок шаблонов, входящий в состав Laravel. В отличие от некоторых шаблонизаторов PHP, Blade не ограничивает вас в использовании обычного "сырого" кода PHP в ваших шаблонах. На самом деле, все шаблоны Blade компилируются в обычный PHP-код и кешируются до тех пор, пока не будут изменены, что означает, что Blade добавляет фактически нулевую нагрузку вашему приложению. Файлы шаблонов Blade используют расширение файла .blade.php
и обычно хранятся в каталоге resources/views
.
Шаблоны Blade могут быть возвращены из маршрутов или контроллера с помощью глобального помощника view
. Конечно, как упоминалось в документации по HTML-шаблонам, данные могут быть переданы в шаблоны Blade, используя второй аргумент помощника view
:
Route::get('/', function () {
return view('greeting', ['name' => 'Finn']);
});
Хотите повысить эффективность ваших шаблонов Blade и легко создавать динамические интерфейсы? Обратите внимание на Laravel Livewire. Livewire позволяет создавать компоненты Blade, дополненные динамической функциональностью, которая обычно доступна только благодаря фреймворкам фронтенда, таким как React или Vue. Такой подход отлично подходит для создания современных, реактивных интерфейсов без сложностей, связанных с отрисовкой на клиентской стороне или сборкой, присущими многим JavaScript-фреймворкам.
Вы можете отображать данные, которые передаются в шаблоны Blade, заключив переменную в фигурные скобки. Например, учитывая следующий маршрут:
Route::get('/', function () {
return view('welcome', ['name' => 'Samantha']);
});
Вы можете отобразить содержимое переменной name
следующим образом:
Привет, {{ $name }}.
Note
Выражения вывода {{ }}
Blade автоматически отправляются через функцию htmlspecialchars
PHP для предотвращения XSS-атак.
Вы не ограничены отображением содержимого переменных, переданных в шаблон. Вы также можете вывести результаты любой функции PHP. Фактически, вы можете поместить любой PHP-код в выражение вывода Blade:
Текущее UNIX-время {{ time() }}.
По умолчанию Blade (и Laravel функция e
) будет дважды кодировать объекты HTML. Если вы хотите отключить двойное кодирование, вызовите метод Blade::withoutDoubleEncoding
в методе boot
вашего AppServiceProvider
:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Загрузка любых служб приложения.
*/
public function boot(): void
{
Blade::withoutDoubleEncoding();
}
}
По умолчанию, выражения вывода {{ }}
Blade автоматически отправляются через функцию htmlspecialchars
PHP для предотвращения XSS-атак. Если вы не хотите, чтобы ваши данные были экранированы, вы можете использовать следующий синтаксис:
Привет, {!! $name !!}.
Warning
Будьте очень осторожны при выводе содержимого, полученного от пользователей вашего приложения. Обычно следует использовать экранированный синтаксис двойных фигурных скобок для предотвращения атак XSS при отображении данных, предоставленных пользователем.
Поскольку во многих фреймворках JavaScript также используются «фигурные» скобки, чтобы указать, что данное выражение должно отобразиться в браузере, вы можете использовать символ @
, чтобы сообщить движку Blade, что выражение должно остаться нетронутым. Например:
<h1>Laravel</h1>
Привет, @{{ name }}.
В этом примере Blade удалит символ @
; однако выражение {{ name }}
останется нетронутым движком Blade, что позволит обработать его вашим фреймворком JavaScript.
Символ @
также используется для исключения из обработки директив Blade:
{{-- Шаблон Blade --}}
@@if()
<!-- Вывод HTML -->
@if()
Иногда вы можете передать массив вашему шаблону с намерением отобразить его как JSON, чтобы инициализировать переменную JavaScript. Например:
<script>
var app = <?php echo json_encode($array); ?>;
</script>
Однако вместо ручного вызова json_encode
, вы можете использовать метод Illuminate\Support\Js::from
. Метод from
принимает те же аргументы, что и функция PHP json_encode
; однако это гарантирует, что полученный JSON будет правильно экранирован для включения в кавычки HTML. Метод from
вернет строковый оператор JavaScript JSON.parse
, который преобразует данный объект или массив в допустимый объект:
<script>
var app = {{ Illuminate\Support\Js::from($array) }};
</script>
Последние версии приложения Laravel включают фасад Js
, который обеспечивает удобный доступ к этой функции в ваших шаблонах Blade:
<script>
var app = {{ Js::from($array) }};
</script>
Warning
Вы должны использовать директиву Js::from
только для отображения существующих переменных как JSON. Шаблонизатор Blade основан на регулярных выражениях, и попытки передать сложное выражение в директиву могут вызвать неожиданные сбои.
Если вы отображаете переменные JavaScript в крупной части своего шаблона, вы можете заключить HTML в директиву @verbatim
, чтобы вам не приходилось добавлять префикс @
к каждому выражению вывода Blade:
@verbatim
<div class="container">
Hello, {{ name }}.
</div>
@endverbatim
Помимо наследования шаблонов и отображения данных, Blade также содержит удобные псевдонимы для общих структур управления PHP, таких, как условные операторы и циклы. Эти директивы обеспечивают очень чистый и лаконичный способ работы со структурами управления PHP, но при этом остаются схожими со своими аналогами PHP.
Вы можете создавать операторы if
, используя директивы @if
, @elseif
, @else
, и @endif
. Эти директивы работают так же, как и их аналоги в PHP:
@if (count($records) === 1)
У меня есть одна запись!
@elseif (count($records) > 1)
У меня есть несколько записей!
@else
У меня нет записей!
@endif
Для удобства Blade также содержит директиву @unless
:
@unless (Auth::check())
Вы не вошли в систему.
@endunless
В дополнение к уже обсужденным условным директивам, директивы @isset
и @empty
могут использоваться в качестве удобных ярлыков для соответствующих функций PHP:
@isset($records)
// Переменная $records определена и не равна null...
@endisset
@empty($records)
// Переменная $records считается «пустой»...
@endempty
Директивы @auth
и @guest
могут использоваться для быстрого определения, является ли текущий пользователь аутентифицированным или считается гостем:
@auth
// Пользователь аутентифицирован...
@endauth
@guest
// Пользователь не аутентифицирован...
@endguest
При необходимости вы можете указать охранника аутентификации для проверки при использовании директив @auth
и @guest
:
@auth('admin')
// Пользователь аутентифицирован...
@endauth
@guest('admin')
// Пользователь не аутентифицирован...
@endguest
Вы можете проверить, запущено ли приложение в эксплуатационном окружении, с помощью директивы @production
:
@production
// Содержимое, отображаемое только в эксплуатационном окружении...
@endproduction
Или вы можете определить, работает ли приложение в конкретной среде, с помощью директивы @env
:
@env('staging')
// Приложение запущено в «переходном» окружении...
@endenv
@env(['staging', 'production'])
// Приложение запущено в «переходном» или «рабочем» окружении...
@endenv
Вы можете определить, есть ли в секции наследуемого шаблона содержимое, используя директиву @hasSection
:
@hasSection('navigation')
<div class="pull-right">
@yield('navigation')
</div>
<div class="clearfix"></div>
@endif
Вы можете использовать директиву sectionMissing
, чтобы определить, что в секции нет содержимого:
@sectionMissing('navigation')
<div class="pull-right">
@include('default-navigation')
</div>
@endif
Директива @session
может использоваться для определения существования значения сессии. Если значение сессии существует, содержимое шаблона внутри директив @session
и @endsession
будет оценено. Внутри содержимого директивы @session
вы можете использовать переменную $value
для вывода значения сессии:
@session('status')
<div class="p-4 bg-green-100">
{{ $value }}
</div>
@endsession
Операторы Switch могут быть созданы с использованием директив @switch
, @case
, @break
, @default
и @endswitch
:
@switch($i)
@case(1)
Первый case...
@break
@case(2)
Второй case...
@break
@default
Case по умолчанию...
@endswitch
В дополнение к условным операторам, Blade содержит простые директивы для работы со структурами циклов PHP. Опять же, каждая из этих директив работает так же, как и их аналоги в PHP:
@for ($i = 0; $i < 10; $i++)
Текущее значение {{ $i }}
@endfor
@foreach ($users as $user)
<p>Это пользователь {{ $user->id }}</p>
@endforeach
@forelse ($users as $user)
<li>{{ $user->name }}</li>
@empty
<p>Нет пользователей</p>
@endforelse
@while (true)
<p>Я зацикливаюсь навсегда.</p>
@endwhile
Note
Во время повторения цикла 'foreach' вы можете использовать переменную Loop, чтобы получить информацию о цикле, например, находитесь ли вы в первой или последней итерации цикла.
При использовании циклов вы также можете пропустить текущую итерацию или завершить цикл, используя директивы @continue
и @break
:
@foreach ($users as $user)
@if ($user->type == 1)
@continue
@endif
<li>{{ $user->name }}</li>
@if ($user->number == 5)
@break
@endif
@endforeach
Вы также можете включить в объявление директивы условие продолжения или прерывания:
@foreach ($users as $user)
@continue($user->type == 1)
<li>{{ $user->name }}</li>
@break($user->number == 5)
@endforeach
Во время повторения цикла foreach
доступна переменная $loop
. Она обеспечивает доступ к некоторой полезной информации, например, индекс текущего цикла, первая это или последняя итерация цикла:
@foreach ($users as $user)
@if ($loop->first)
Это первая итерация.
@endif
@if ($loop->last)
Это последняя итерация.
@endif
<p>Это пользователь {{ $user->id }}</p>
@endforeach
При нахождении во вложенном цикле, вы можете получить доступ к переменной $loop
родительского цикла через свойство parent
:
@foreach ($users as $user)
@foreach ($user->posts as $post)
@if ($loop->parent->first)
Это первая итерация родительского цикла.
@endif
@endforeach
@endforeach
Переменная $loop
также содержит множество других полезных свойств:
Свойство | Описание |
---|---|
$loop->index |
Индекс текущей итерации цикла (начинается с 0). |
$loop->iteration |
Текущая итерация цикла (начинается с 1). |
$loop->remaining |
Итерации, оставшиеся в цикле. |
$loop->count |
Общее количество элементов в итерируемом массиве. |
$loop->first |
Первая ли это итерация цикла. |
$loop->last |
Последняя ли это итерация цикла. |
$loop->even |
Четная ли это итерация цикла. |
$loop->odd |
Нечетная ли это итерация цикла. |
$loop->depth |
Уровень вложенности текущего цикла. |
$loop->parent |
Переменная родительского цикла во вложенном цикле. |
Директива @class
осуществляет построение строки css-классов исходя из заданных условий. Директива принимает массив классов, где ключ массива содержит класс или классы, которые вы хотите добавить, а значение является булевым выражением. Если элемент массива имеет числовой ключ, он всегда будет включен в отрисованный список классов:
@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>
Также, директива @style
может использоваться, чтобы условно добавлять встроенные стили CSS к HTML-элементу:
@php
$isActive = true;
@endphp
<span @style([
'background-color: red',
'font-weight: bold' => $isActive,
])></span>
<span style="background-color: red; font-weight: bold;"></span>
Для удобства, вы можете использовать директиву @checked
, чтобы легко указать, должен ли данный флажок HTML быть "отмеченным". Эта директива будет выводить checked
, если условие выполнится:
<input
type="checkbox"
name="active"
value="active"
@checked(old('active', $user->active))
/>
Аналогично, директива @selected
может использоваться, чтобы указать, должен ли заданный вариант выбора быть "выбранным":
<select name="version">
@foreach ($product->versions as $version)
<option value="{{ $version }}" @selected(old('version') == $version)>
{{ $version }}
</option>
@endforeach
</select>
Кроме того, директива @disabled
может использоваться, чтобы указать, должен ли данный элемент быть "отключенным":
<button type="submit" @disabled($errors->isNotEmpty())>Отправить</button>
Более того, директива @readonly
может быть использована, чтобы указать, должен ли данный элемент быть "только для чтения":
<input
type="email"
name="email"
value="email@laravel.com"
@readonly($user->isNotAdmin())
/>
Кроме того, директива @required
может быть использована, чтобы указать, должен ли данный элемент быть "обязательным":
<input
type="text"
name="title"
value="title"
@required($user->isAdmin())
/>
Note
Хотя вы можете использовать директиву @include
, компоненты Blade содержат аналогичный функционал и предлагают несколько преимуществ по сравнению с директивой @include
, например привязку данных и атрибутов.
Директива @include
Blade позволяет вам включать шаблоны из другого шаблона. Все переменные, доступные для родительского шаблона, будут доступны для включенного шаблона:
<div>
@include('shared.errors')
<form>
<!-- Содержимое формы -->
</form>
</div>
Включенный шаблон унаследует все данные, доступные в родительском шаблоне, но вы также можете передать массив дополнительных данных, которые должны быть доступны для включенного шаблона:
@include('view.name', ['status' => 'complete'])
Если вы попытаетесь включить несуществующий шаблон, Laravel выдаст ошибку. Если вы хотите включить шаблон, который может присутствовать или отсутствовать, вам следует использовать директиву @includeIf
:
@includeIf('view.name', ['status' => 'complete'])
Если вы хотите включить шаблон в зависимости от результата логического выражения, возвращающего либо true
, либо false
, то используйте директивы @includeWhen
и @includeUnless
:
@includeWhen($boolean, 'view.name', ['status' => 'complete'])
@includeUnless($boolean, 'view.name', ['status' => 'complete'])
Чтобы включить первый существующий шаблон из переданного массива шаблонов, вы можете использовать директиву includeFirst
:
@includeFirst(['custom.admin', 'admin'], ['status' => 'complete'])
Warning
Вам следует избегать использования в ваших шаблонах Blade констант __DIR__
и __FILE__
, поскольку они будут ссылаться на расположение кешированного, скомпилированного шаблона.
Вы можете скомбинировать циклы и подключение шаблона в одну строку с помощью директивы Blade @each
:
@each('view.name', $jobs, 'job')
Первый аргумент директивы @each
– это шаблон, отображаемый для каждого элемента в массиве или коллекции. Второй аргумент – это массив или коллекция, которую вы хотите перебрать. Третий аргумент – это имя переменной, которая будет присвоена текущей итерации в шаблоне. Так, например, если вы выполняете итерацию по массиву jobs
, обычно вам нужно обращаться к каждому элементу как к переменной job
в шаблоне. Ключ массива для текущей итерации будет доступен как переменная key
в шаблоне.
Вы можете передать четвертый аргумент директиве @each
. Этот аргумент определяет шаблон, который будет отображаться, если переданный массив пуст.
@each('view.name', $jobs, 'job', 'view.empty')
Warning
Шаблоны, отображаемые с помощью @each
, не наследуют переменные родительского шаблона. Если дочернему шаблону требуются эти переменные, вам следует использовать вместо них директивы @foreach
и @include
.
Директива @once
позволяет вам определить часть шаблона, которая будет проанализирована только один раз за цикл визуализации. Это может быть полезно для вставки переданного фрагмента JavaScript в подвал страницы с помощью стеков. Например, если вы отображаете переданный компонент в цикле, то бывает необходимо разместить JavaScript в подвале при визуализации компонента только единожды:
@once
@push('scripts')
<script>
// Ваш JavaScript...
</script>
@endpush
@endonce
Поскольку директива @once
часто используется в сочетании с директивами @push
или @prepend
, для удобства доступны директивы @pushOnce
и @prependOnce
:
@pushOnce('scripts')
<script>
// Ваш JavaScript...
</script>
@endPushOnce
В крайних ситуациях можно встроить PHP-код в ваши шаблоны. Вы можете использовать директиву @php
Blade для размещения блока простого PHP в вашем шаблоне:
@php
$counter = 1;
@endphp
Или, если вам нужно использовать только PHP для импорта класса, вы можете использовать директиву @use
:
@use('App\Models\Flight')
Второй аргумент может быть использован в директиве @use
для указания псевдонима импортируемого класса:
@use('App\Models\Flight', 'FlightModel')
Blade также позволяет вам определять комментарии в ваших шаблонах. Однако, в отличие от комментариев HTML, комментарии Blade не будут включены в результирующий HTML, возвращаемый вашим приложением:
{{-- Этот комментарий не будет присутствовать в отображаемом HTML. --}}
Компоненты и слоты предоставляют те же преимущества, что и секции, макеты и включение шаблона из другого шаблона; однако, некоторым может быть легче понять мысленную модель компонентов и слотов. Есть два подхода к написанию компонентов: компоненты на основе классов и анонимные компоненты.
Чтобы создать компонент на основе класса, вы можете использовать команду make:component
Artisan. Чтобы проиллюстрировать, как использовать компоненты, мы создадим простой компонент Alert
. Команда make:component
поместит компонент в каталог app/View/Components
:
php artisan make:component Alert
Команда make: component
также создаст шаблон для компонента. Шаблон будет помещен в каталог resources/views/components
. При написании компонентов для вашего собственного приложения компоненты автоматически обнаруживаются в каталогах app/View/Components
и resources/views/components
, поэтому дополнительная регистрация компонентов обычно не требуется.
Вы также можете создавать компоненты в подкаталогах:
php artisan make:component Forms/Input
Приведенная выше команда создаст компонент Input
в каталоге app/View/Components/Forms
, а шаблон будет помещен в каталог resources/views/components/forms
.
Если вы хотите создать анонимный компонент (компонент только с шаблоном в Blade без класса), вы можете использовать флаг --view
при вызове команды make:component
:
php artisan make:component forms.input --view
Вышеприведенная команда создаст файл Blade по пути resources/views/components/forms/input.blade.php
, который может быть отображен как компонент с помощью <x-forms.input />
.
При написании компонентов для вашего собственного приложения компоненты автоматически обнаруживаются в каталогах app/View/Components
и resources/views/components
.
Однако, если вы создаете пакет, который использует компоненты Blade, вам необходимо вручную зарегистрировать класс компонента и его псевдоним HTML-тега. Вы должны зарегистрировать свои компоненты в методе boot
поставщика служб вашего пакета:
use Illuminate\Support\Facades\Blade;
/**
* Загрузка любых служб пакета.
*/
public function boot(): void
{
Blade::component('package-alert', Alert::class);
}
После того как ваш компонент был зарегистрирован, он может быть отображен с использованием псевдонима тега:
<x-package-alert/>
Как вариант, вы можете использовать метод componentNamespace
для автоматической загрузки классов компонентов по соглашению. Например, пакет Nightshade
может иметь компоненты Calendar
и ColorPicker
, которые находятся в пространстве имен Package\Views\Components
:
use Illuminate\Support\Facades\Blade;
/**
* Загрузка любых служб пакета.
*/
public function boot(): void
{
Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}
Это позволит использовать компоненты пакета в пространстве имен их поставщиков, используя синтаксис x-package-name::
:
<x-nightshade::calendar />
<x-nightshade::color-picker />
Blade автоматически обнаружит класс, связанный с этим компонентом, используя «верблюжий регистр» имени компонента. Подкаталоги также поддерживаются с использованием «точечной» нотации.
Для отображения компонента вы можете использовать тег компонента Blade в одном из ваших шаблонов Blade. Теги компонентов Blade начинаются со строки x-
, за которой следует имя в «шашлычном регистре» класса компонента:
<x-alert/>
<x-user-profile/>
Если класс компонента имеет вложенность в каталоге app/View/Components
, то вы можете использовать символ .
для обозначения вложенности каталогов. Например, если мы предполагаем, что компонент находится в app/View/Components/Inputs/Button.php
, то мы можем отобразить его так:
<x-inputs.button/>
Если вы хотите выборочно отображать ваш компонент, вы можете указать метод shouldRender
в классе вашего компонента. Если результат метода shouldRender
равен false
, то компонент не будет отображаться:
use Illuminate\Support\Str;
/**
* Определяет, должен ли компонент отображаться
*/
public function shouldRender(): bool
{
return Str::length($this->message) > 0;
}
Иногда компоненты являются частью группы компонентов, и вам может потребоваться сгруппировать связанные компоненты в одном каталоге. Например, представьте себе компонент «card» со следующей структурой классов:
App\Views\Components\Card\Card
App\Views\Components\Card\Header
App\Views\Components\Card\Body
Поскольку корневой компонент Card
вложен в каталог Card
, вы можете ожидать, что вам потребуется визуализировать компонент через <x-card.card>
. Однако, когда имя файла компонента совпадает с именем каталога компонента, Laravel автоматически предполагает, что компонент является «корневым» компонентом, и позволяет отображать компонент без повторения имени каталога:
<x-card>
<x-card.header>...</x-card.header>
<x-card.body>...</x-card.body>
</x-card>
Вы можете передавать данные в компоненты Blade, используя атрибуты HTML. Жестко запрограммированные примитивные значения могут быть переданы компоненту с помощью простых строк атрибутов HTML. Выражения и переменные PHP следует передавать компоненту через атрибуты, которые используют символ :
в качестве префикса:
<x-alert type="error" :message="$message"/>
Вы должны определить необходимые данные компонента в его конструкторе класса. Все общедоступные свойства компонента будут автоматически доступны в шаблоне компонента. Нет необходимости передавать данные в шаблон из метода render
компонента:
<?php
namespace App\View\Components;
use Illuminate\View\Component;
use Illuminate\View\View;
class Alert extends Component
{
/**
* Создать экземпляр компонента.
*/
public function __construct(
public string $type,
public string $message,
) {}
/**
* Получить шаблон / содержимое, представляющее компонент.
*/
public function render(): View
{
return view('components.alert');
}
}
Когда ваш компонент визуализируется, вы можете отображать содержимое общедоступных переменных вашего компонента, выводя переменные по имени:
<div class="alert alert-{{ $type }}">
{{ $message }}
</div>
Аргументы конструктора компонентов следует указывать с помощью camelCase
, а при обращении к именам аргументов в ваших атрибутах HTML следует использовать kebab-case
. Например, учитывая следующий конструктор компонента:
/**
* Создать экземпляр компонента.
*/
public function __construct(
public string $alertType,
) {}
Аргумент $alertType
может быть передан компоненту следующим образом:
<x-alert alert-type="danger" />
При передаче атрибутов компонентам вы также можете использовать "сокращенный синтаксис атрибутов". Это удобно, поскольку имена атрибутов часто совпадают с именами переменных, к которым они относятся:
{{-- Сокращенный синтаксис атрибутов... --}}
<x-profile :$userId :$name />
{{-- Эквивалентно... --}}
<x-profile :user-id="$userId" :name="$name" />
Поскольку некоторые фреймворки JavaScript, такие, как Alpine.js, также используют атрибуты с префиксом двоеточия, вы можете использовать префикс с двойным двоеточием (::
), чтобы сообщить Blade, что атрибут не является выражением PHP. Например, учитывая следующий компонент:
<x-button ::class="{ danger: isDeleting }">
Отправить
</x-button>
Blade отобразит следующий HTML-код:
<button :class="{ danger: isDeleting }">
Отправить
</button>
В дополнение к общедоступным переменным, доступным для вашего шаблона компонента, могут быть вызваны любые общедоступные методы компонента. Например, представьте компонент, у которого есть метод isSelected
:
/**
* Определить, является ли переданная опция выбранной.
*/
public function isSelected(string $option): bool
{
return $option === $this->selected;
}
Вы можете выполнить этот метод из своего шаблона компонента, вызвав переменную, соответствующую имени метода:
<option {{ $isSelected($value) ? 'selected' : '' }} value="{{ $value }}">
{{ $label }}
</option>
Компоненты Blade также позволяют получить доступ к имени компонента, атрибутам и слоту внутри метода render
класса. Однако, чтобы получить доступ к этим данным, вы должны вернуть замыкание из метода render
вашего компонента:
use Closure;
/**
* Получить шаблон / содержимое, представляющее компонент.
*/
public function render(): Closure
{
return function () {
return '<div {{ $attributes }}>Содержание компонентов</div>';
};
}
Замыкание, возвращаемое методом render
вашего компонента, также может получать массив $data
в качестве единственного аргумента. Этот массив будет содержать несколько элементов, предоставляющих информацию о компоненте:
return function (array $data) {
// $data['componentName'];
// $data['attributes'];
// $data['slot'];
return '<div {{ $attributes }}>Содержание компонентов</div>';
}
Warning
Элементы массива $data
никогда не должны быть непосредственно встроены в строку Blade, возвращаемую вашим методом render
, так как это может привести к удаленному выполнению кода через вредоносное содержимое атрибута.
componentName
эквивалентно имени, используемому в HTML-теге после префикса x-
. Таким образом, componentName
компонента <x-alert />
будет alert
. Элемент attributes
будет содержать все атрибуты, которые присутствовали в HTML-теге. Элемент slot
– это экземпляр Illuminate\Support\HtmlString
с содержимым слота компонента.
Замыкание должно возвращать строку. Если возвращенная строка соответствует существующему шаблону, то этот шаблон будет отрисован; в противном случае возвращенная строка будет оцениваться как встроенный шаблон Blade.
Если вашему компоненту требуются зависимости из контейнера служб Laravel, то вы можете указать их перед любыми атрибутами данных компонента, и они будут автоматически внедрены контейнером:
use App\Services\AlertCreator;
/**
* Создать экземпляр компонента.
*/
public function __construct(
public AlertCreator $creator,
public string $type,
public string $message,
) {}
Если вы хотите, чтобы некоторые публичные методы или свойства не использовались как переменные в шаблоне компонента, вы можете добавить их в свойство массива $except
в вашем компоненте:
<?php
namespace App\View\Components;
use Illuminate\View\Component;
class Alert extends Component
{
/**
* Свойства / методы, которые не должны использоваться в шаблоне компонента.
*
* @var array
*/
protected $except = ['type'];
/**
* Создаие экземпляра компонента.
*/
public function __construct(
public string $type,
) {}
}
Мы уже рассмотрели, как передавать атрибуты данных в компонент; иногда требуется указать дополнительные атрибуты HTML, такие, как class
, которые не являются частью данных, необходимых для функционирования компонента. Как правило, вы хотите передать эти дополнительные атрибуты корневому элементу шаблона компонента. Например, представьте, что мы хотим отобразить компонент alert
следующим образом:
<x-alert type="error" :message="$message" class="mt-4"/>
Все атрибуты, которые не являются частью конструктора компонента, будут автоматически добавлены в «коллекцию атрибутов» компонента. Эта коллекция атрибутов автоматически становится доступной для компонента через переменную $attributes
. Все атрибуты могут отображаться в компоненте путем вывода этой переменной:
<div {{ $attributes }}>
<!-- Содержание компонента -->
</div>
Warning
Использование таких директив, как @env
в тегах компонентов в настоящее время не поддерживается. Например, <x-alert :live="@env('production')"/>
не будет компилироваться.
Иногда требуется указать значения по умолчанию для атрибутов или добавить дополнительные значения в некоторые атрибуты компонента. Для этого вы можете использовать метод merge
коллекции атрибутов. Этот метод особенно полезен для определения набора CSS-классов по умолчанию, которые всегда должны применяться к компоненту:
<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
{{ $message }}
</div>
Если предположить,
<x-alert type="error" :message="$message" class="mb-4"/>
Окончательный обработанный HTML-код компонента будет выглядеть следующим образом:
<div class="alert alert-error mb-4">
<!-- Содержимое переменной $message -->
</div>
По желанию можно объединить классы, если указанное условие истинно. Вы можете сделать это с помощью метода class
, принимающий массив классов, где ключ массива содержит класс или классы, которые вы хотите добавить, а значение является логическим выражением. Если элемент массива имеет числовой ключ, то он всегда будет добавлен в конечный список классов:
<div {{ $attributes->class(['p-4', 'bg-red' => $hasError]) }}>
{{ $message }}
</div>
Если вам нужно объединить другие атрибуты в свой компонент, вы можете связать метод merge
с методом class
:
<button {{ $attributes->class(['p-4'])->merge(['type' => 'button']) }}>
{{ $slot }}
</button>
Note
Если вам нужно условно скомпилировать классы для других элементов HTML, которые не должны получать объединенные атрибуты, вы можете использовать директиву @class
.
При слиянии атрибутов, которые не являются атрибутами класса, значения, предоставленные методу merge
, будут считаться значениями атрибута по умолчанию. Однако, в отличие от атрибута class
, эти атрибуты не будут объединены с указанными значениями атрибутов. Вместо этого они будут перезаписаны. Например, реализация компонента button
может выглядеть следующим образом:
<button {{ $attributes->merge(['type' => 'button']) }}>
{{ $slot }}
</button>
Чтобы отобразить компонент кнопки с настраиваемым type
, его можно указать при использовании компонента. Если тип не указан, будет использоваться тип button
, определенный по умолчанию:
<x-button type="submit">
Отправить
</x-button>
Обработанный HTML-код компонента button
в этом примере будет:
<button type="submit">
Отправить
</button>
Если вы хотите, чтобы атрибут, отличный от class
, имел значение по умолчанию и указанное значение, объединенные вместе, вы можете использовать метод prepends
. В этом примере атрибут data-controller
всегда будет начинаться с profile-controller
, а любые дополнительные указанные значения data-controller
будут помещены после этого значения по умолчанию:
<div {{ $attributes->merge(['data-controller' => $attributes->prepends('profile-controller')]) }}>
{{ $slot }}
</div>
Вы можете фильтровать атрибуты, используя метод filter
. Этот метод принимает замыкание, которое должно возвращать true
, если вы хотите сохранить атрибут в коллекции атрибутов:
{{ $attributes->filter(fn (string $value, string $key) => $key == 'foo') }}
Для удобства вы можете использовать метод whereStartsWith
для получения всех атрибутов, ключи которых начинаются с указанной строки:
{{ $attributes->whereStartsWith('wire:model') }}
И наоборот, метод whereDoesntStartWith
может быть использован для исключения всех атрибутов, ключи которых начинаются с указанной строки:
{{ $attributes->whereDoesntStartWith('wire:model') }}
Используя метод first
, вы можете отобразить первый атрибут в указанной коллекции атрибутов:
{{ $attributes->whereStartsWith('wire:model')->first() }}
Если вы хотите проверить, присутствует ли атрибут в компоненте, вы можете использовать метод has
. Этот метод принимает имя атрибута в качестве единственного аргумента и возвращает логическое значение, указывающее, присутствует ли атрибут:
@if ($attributes->has('class'))
<div>Атрибут class присутствует</div>
@endif
Если передан массив в метод has
, то он проверит, присутствуют ли все указанные атрибуты у компонента:
@if ($attributes->has(['name', 'class']))
<div>Все указанные атрибуты присутствуют</div>
@endif
Метод hasAny
может быть использован для определения, присутствует ли хотя бы один из указанных атрибутов у компонента:
@if ($attributes->hasAny(['href', ':href', 'v-bind:href']))
<div>Один из указанных атрибутов присутствует</div>
@endif
Вы можете получить значение конкретного атрибута, используя метод get
:
{{ $attributes->get('class') }}
По умолчанию некоторые ключевые слова зарезервированы для внутреннего использования Blade при визуализации компонентов. Следующие ключевые слова не могут быть определены как публичные свойства или имена методов в ваших компонентах:
data
render
resolveView
shouldRender
view
withAttributes
withName
Вам часто потребуется передавать дополнительный контент вашему компоненту через «слоты». Слоты компонентов отображаются путем вывода переменной $slot
. Чтобы изучить эту концепцию, представим, что компонент alert
имеет следующую разметку:
<!-- /resources/views/components/alert.blade.php -->
<div class="alert alert-danger">
{{ $slot }}
</div>
Мы можем передавать контент в slot
, вставив контент в компонент:
<x-alert>
<strong>Упс!</strong> Что-то пошло не так!
</x-alert>
Иногда компоненту может потребоваться отрисовать несколько разных слотов в разных местах внутри компонента. Давайте модифицируем наш компонент оповещения, чтобы учесть вставку слота title
:
<!-- /resources/views/components/alert.blade.php -->
<span class="alert-title">{{ $title }}</span>
<div class="alert alert-danger">
{{ $slot }}
</div>
Вы можете определить содержимое именованного слота с помощью тега x-slot
. Любой контент, не указанный в явном теге x-slot
, будет передан компоненту в переменной $slot
:
<x-alert>
<x-slot:title>
Ошибка сервера
</x-slot>
<strong>Упс!</strong> Что-то пошло не так!
</x-alert>
Вы можете вызвать метод слота isEmpty
, чтобы определить, содержит ли он контент:
<span class="alert-title">{{ $title }}</span>
<div class="alert alert-danger">
@if ($slot->isEmpty())
Это содержимое по умолчанию, если слот пуст.
@else
{{ $slot }}
@endif
</div>
Кроме того, метод hasActualContent
может быть использован для определения, содержит ли слот какой-либо «фактический» контент, не являющийся HTML-комментарием:
@if ($slot->hasActualContent())
В области нет комментариев.
@endif
Если вы использовали фреймворк JavaScript, такой, как Vue, то вы, возможно, знакомы со «слотами с ограниченной областью видимости», которые позволяют получать доступ к данным или методам из компонента в вашем слоте. Вы можете добиться аналогичного поведения в Laravel, определив общедоступные методы или свойства в вашем компоненте и получив доступ к компоненту в вашем слоте через переменную $component
. В этом примере мы предположим, что компонент x-alert
имеет общедоступный метод formatAlert
, определенный в его классе компонента:
<x-alert>
<x-slot:title>
{{ $component->formatAlert('Ошибка сервера') }}
</x-slot>
<strong>Упс!</strong> Что-то пошло не так!
</x-alert>
Как и в компонентах Blade, вы можете назначать слотам дополнительные атрибуты, например, имена классов CSS:
<x-card class="shadow-sm">
<x-slot:heading class="font-bold">
Заголовок
</x-slot>
Содержание
<x-slot:footer class="text-sm">
Нижний колонтитул
</x-slot>
</x-card>
Чтобы взаимодействовать с атрибутами слота, можно обратиться к свойству attributes
переменной слота. Для получения дополнительной информации о том, как взаимодействовать с атрибутами, обратитесь к документации по атрибутам компонентов:
@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>
Для очень маленьких компонентов может показаться обременительным управлять как классом компонента, так и шаблоном компонента. По этой причине вы можете вернуть разметку компонента прямо из метода render
:
/**
* Получить шаблон / содержимое, представляющее компонент.
*/
public function render(): string
{
return <<<blade
<div class="alert alert-danger">
{{ $slot }}
</div>
blade;
}
Чтобы создать компонент, который использует встроенный шаблон, вы можете использовать параметр --inline
при выполнении команды make:component
:
php artisan make:component Alert --inline
Иногда вам может понадобиться отрисовать компонент, но вы не знаете, какой компонент должен быть отрисован на этапе выполнения. В этой ситуации вы можете использовать встроенный компонент dynamic-component
в Laravel, чтобы отрисовать компонент на основе значения или переменной, полученных на этапе выполнения:
// $componentName = "secondary-button";
<x-dynamic-component :component="$componentName" class="mt-4" />
Warning
Следующая документация по ручной регистрации компонентов в основном применима к тем, кто пишет пакеты Laravel, включающие компоненты отображения. Если вы не пишете пакет, эта часть документации по компонентам может быть неактуальной для вас.
Когда вы создаете компоненты для своего приложения, они автоматически обнаруживаются в каталоге app/View/Components
и каталоге resources/views/components
.
Однако, если вы создаете пакет, использующий компоненты Blade, или помещаете компоненты в нестандартные каталоги, вам потребуется вручную зарегистрировать класс вашего компонента и его псевдоним HTML-тега, чтобы Laravel знал, где найти компонент. Обычно вы регистрируете свои компоненты в методе boot
сервис-провайдера вашего пакета:
use Illuminate\Support\Facades\Blade;
use VendorPackage\View\Components\AlertComponent;
/**
* Инициализация сервисов вашего пакета.
*/
public function boot(): void
{
Blade::component('package-alert', AlertComponent::class);
}
После того, как ваш компонент будет зарегистрирован, его можно отрисовать с использованием его псевдонима тега:
<x-package-alert/>
В качестве альтернативы вы можете использовать метод componentNamespace
для автозагрузки классов компонентов согласно конвенции. Например, пакет Nightshade
может содержать компоненты Calendar
и ColorPicker
, которые находятся в пространстве имен Package\Views\Components
:
use Illuminate\Support\Facades\Blade;
/**
* Инициализация сервисов вашего пакета.
*/
public function boot(): void
{
Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}
Это позволит использовать компоненты пакета с использованием пространства имен вендора с использованием синтаксиса package-name::
:
<x-nightshade::calendar />
<x-nightshade::color-picker />
Blade автоматически обнаружит класс, связанный с этим компонентом, преобразовав имя компонента в паскальный регистр. Также поддерживаются подкаталоги, используя синтаксис "точка".
Подобно встроенным компонентам, анонимные компоненты предоставляют механизм для управления компонентом через один файл. Однако анонимные компоненты используют один файл шаблона, но не имеют связанного с компонентом класса. Чтобы определить анонимный компонент, вам нужно только разместить шаблон Blade в вашем каталоге resources/views/components
. Например, если вы определили компонент в resources/views/components/alert.blade.php
, вы можете просто отобразить его так:
<x-alert/>
Вы можете использовать символ .
, чтобы указать, вложен ли компонент в каталоге components
. Например, если компонент определен в resources/views/components/inputs/button.blade.php
, вы можете отобразить его так:
<x-inputs.button/>
Иногда, когда компонент состоит из множества шаблонов Blade, вы можете захотеть сгруппировать шаблоны данного компонента в одном каталоге. Например, представьте компонент "аккордеон" со следующей структурой каталогов:
/resources/views/components/accordion.blade.php
/resources/views/components/accordion/item.blade.php
Такая структура каталога позволяет отобразить компонент аккордеона и его элемент следующим образом:
<x-accordion>
<x-accordion.item>
...
</x-accordion.item>
</x-accordion>
Однако, чтобы отобразить компонент аккордеона через x-accordion
, мы были вынуждены поместить шаблон компонента аккордеона "index" в каталог resources/views/components
, вместо того, чтобы вложить его в каталог accordion
с другими шаблонами, связанными с аккордеоном.
К счастью, Blade позволяет вам разместить файл, соответствующий имени каталога компонента, внутри самого каталога компонента. Если этот шаблон существует, его можно отобразить как «корневой» элемент компонента, даже если он вложен в каталог. Итак, мы можем продолжать использовать тот же синтаксис Blade, что и в примере выше; однако мы изменим структуру наших каталогов следующим образом:
/resources/views/components/accordion/accordion.blade.php
/resources/views/components/accordion/item.blade.php
Поскольку анонимные компоненты не имеют ассоциированного класса, вы можете задаться вопросом, как можно различить, какие данные должны быть переданы компоненту как переменные, а какие атрибуты должны быть помещены в коллекцию атрибутов компонента.
Вы можете указать, какие атрибуты следует рассматривать как переменные данных, используя директиву @props
в верхней части шаблона Blade вашего компонента. Все остальные атрибуты компонента будут доступны через коллекцию атрибутов компонента. Если вы хотите присвоить переменной данных значение по умолчанию, вы можете указать имя переменной в качестве ключа массива и значение по умолчанию в качестве значения массива:
<!-- /resources/views/components/alert.blade.php -->
@props(['type' => 'info', 'message'])
<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
{{ $message }}
</div>
Учитывая приведенное выше определение компонента, мы можем отобразить компонент следующим образом:
<x-alert type="error" :message="$message" class="mb-4"/>
Иногда вам может потребоваться доступ к данным из родительского компонента внутри дочернего компонента. В этих случаях вы можете использовать директиву @aware
. Например, представьте, что мы создаем сложный компонент меню, состоящий из родительского <x-menu>
и дочернего <x-menu.item>
:
<x-menu color="purple">
<x-menu.item>...</x-menu.item>
<x-menu.item>...</x-menu.item>
</x-menu>
Компонент <x-menu>
может иметь следующую реализацию:
<!-- /resources/views/components/menu/index.blade.php -->
@props(['color' => 'gray'])
<ul {{ $attributes->merge(['class' => 'bg-'.$color.'-200']) }}>
{{ $slot }}
</ul>
Поскольку свойство color
было передано только родительскому элементу (<x-menu>
), оно не будет доступно внутри <x-menu.item>
. Однако, если мы воспользуемся директивой @aware
, мы можем сделать ее доступной и внутри <x-menu.item>
:
<!-- /resources/views/components/menu/item.blade.php -->
@aware(['color' => 'gray'])
<li {{ $attributes->merge(['class' => 'text-'.$color.'-800']) }}>
{{ $slot }}
</li>
Warning
Директива @aware
не может обращаться к родительским данным, которые не явно передаются в родительский компонент через HTML-атрибуты. Значения @props
, которые не явно передаются в родительский компонент, не могут быть доступны директиве @aware
.
Как уже обсуждалось ранее, для определения анонимных компонентов обычно использовался шаблон Blade, размещаемый в директории resources/views/components
вашего Laravel-приложения. Однако, возможно, вам потребуется указать другие пути для анонимных компонентов, дополнительно к пути по умолчанию.
Метод anonymousComponentPath
принимает первым аргументом "путь" к расположению анонимного компонента, а вторым аргументом - необязательное "пространство имён" для компонентов. Чаще всего этот метод вызывается из метода boot
одного из ваших провайдеров служб:
/**
* Инициализация сервисов приложения.
*/
public function boot(): void
{
Blade::anonymousComponentPath(__DIR__.'/../components');
}
Если пути компонентов зарегистрированы без указания префикса, как в приведенном выше примере, то компоненты можно использовать в вашем коде Blade без указания соответствующего префикса. Например, если компонент panel.blade.php
существует в указанном пути, его можно использовать следующим образом:
<x-panel />
Вы также можете предоставить "пространство имён" вторым аргументом метода anonymousComponentPath
:
Blade::anonymousComponentPath(__DIR__.'/../components', 'dashboard');
Когда используется префикс, компоненты из этого "пространства имён" можно использовать с префиксом пространства имён и имени компонента:
<x-dashboard::panel />
Большинство веб-приложений поддерживают одинаковый общий макет на разных страницах. Было бы невероятно громоздко и сложно поддерживать наше приложение, если бы нам приходилось повторять весь HTML-макет в каждом создаваемом экране. К счастью, этот макет удобно определить как один компонент Blade, а затем использовать его во всем приложении.
Например, представьте, что мы создаем приложение со списком задач. Мы могли бы определить компонент layout
, который выглядит следующим образом:
<!-- resources/views/components/layout.blade.php -->
<html>
<head>
<title>{{ $title ?? 'Менеджер задач' }}</title>
</head>
<body>
<h1>Задачи</h1>
<hr/>
{{ $slot }}
</body>
</html>
Как только компонент layout
определен, мы можем создать шаблон Blade, который будет использовать этот компонент. В этом примере мы определим простой шаблон, который отображает наш список задач:
<!-- resources/views/tasks.blade.php -->
<x-layout>
@foreach ($tasks as $task)
<div>{{ $task }}</div>
@endforeach
</x-layout>
Помните, что содержимое, внедренное в компонент, по умолчанию будет передано переменной $slot
компонента layout
. Как вы могли заметить, наш layout
также учитывает слот $title
, если он предусмотрен; в противном случае отображается заголовок по умолчанию. Мы можем добавить другой заголовок из нашего шаблона списка задач, используя стандартный синтаксис слотов, описанный в документации по компонентам:
<!-- resources/views/tasks.blade.php -->
<x-layout>
<x-slot:title>
Пользовательский заголовок
</x-slot>
@foreach ($tasks as $task)
<div>{{ $task }}</div>
@endforeach
</x-layout>
Теперь, когда мы определили наш макет и шаблоны списка задач, нам просто нужно вернуть представление task
из маршрута:
use App\Models\Task;
Route::get('/tasks', function () {
return view('tasks', ['tasks' => Task::all()]);
});
Макеты также могут быть созданы с помощью «наследования шаблонов». Это был основной способ создания приложений до появления компонентов.
Для начала рассмотрим простой пример. Сначала мы изучим макет страницы. Поскольку большинство веб-приложений поддерживают одинаковый общий макет на разных страницах, удобно определить этот макет как единый шаблон Blade:
<!-- resources/views/layouts/app.blade.php -->
<html>
<head>
<title>Имя приложения - @yield('title')</title>
</head>
<body>
@section('sidebar')
Это главная боковая панель.
@show
<div class="container">
@yield('content')
</div>
</body>
</html>
Как видите, этот файл содержит типичную разметку HTML. Однако, обратите внимание на директивы @section
и @yield
. Директива @section
, как следует из названия, определяет секцию содержимого, тогда как директива @yield
используется для отображения содержимого секции, предоставленного дочерним шаблоном.
Теперь, когда мы определили макет для нашего приложения, давайте определим дочернюю страницу, которая наследует макет.
При определении дочернего шаблона используйте директиву Blade @extends
, чтобы указать, какой макет дочерний шаблон должен «наследовать». Шаблоны, расширяющие макет Blade, могут добавлять содержимое в секции макета с помощью директив @section
. Помните, как видно из приведенного выше примера, содержимое этих секций будет отображаться в макете с помощью @yield
:
<!-- resources/views/child.blade.php -->
@extends('layouts.app')
@section('title', 'Название страницы')
@section('sidebar')
@@parent
<p>Это добавляется к главной боковой панели.</p>
@endsection
@section('content')
<p>Это содержимое моей страницы.</p>
@endsection
В этом примере секция sidebar
использует директиву @@parent
для добавления (а не перезаписи) содержимого к боковой панели макета. Директива @@parent
будет заменена содержимым макета при визуализации представления.
Note
В отличие от предыдущего примера, нынешняя секция sidebar
заканчивается @endsection
вместо @show
. Директива @endsection
будет только определять секцию, в то время как @show
будет определять и немедленно дополнять секцию.
Директива @yield
также принимает значение по умолчанию в качестве второго параметра. Это значение будет отображено, если дополняемый раздел не определен:
@yield('content', 'Содержимое по умолчанию')
Каждый раз, когда вы определяете HTML-форму в своем приложении, вы должны включать в форму скрытое поле токена CSRF, чтобы посредник защиты от CSRF мог провалидировать запрос. Вы можете использовать директиву @csrf
Blade для генерации поля токена:
<form method="POST" action="/profile">
@csrf
...
</form>
Поскольку HTML-формы не могут выполнять запросы PUT
, PATCH
или DELETE
, вам нужно будет добавить скрытое поле _method
, чтобы подменить эти HTTP-методы. Директива @method
Blade поможет создать для вас такое поле:
<form action="/foo/bar" method="POST">
@method('PUT')
...
</form>
Директива @error
используется для быстрой проверки наличия сообщений об ошибках валидации для конкретного атрибута. В директиве @error
вы можете вывести содержимое переменной $message
для отображения сообщения об ошибке:
<!-- /resources/views/post/create.blade.php -->
<label for="title">Название сообщения</label>
<input
id="title"
type="text"
class="@error('title') is-invalid @enderror"
/>
@error('title')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
Поскольку директива @error
компилируется в оператор "if", вы можете использовать директиву @else
для вывода содержимого, когда для атрибута нет ошибки:
<!-- /resources/views/auth.blade.php -->
<label for="email">Адрес электронной почты</label>
<input
id="email"
type="email"
class="@error('email') is-invalid @else is-valid @enderror"
/>
Вы можете передать имя конкретной коллекции ошибок в качестве второго параметра директивы @error
для получения сообщений об ошибках валидации на страницах, содержащих несколько форм:
<!-- /resources/views/auth.blade.php -->
<label for="email">Адрес электронной почты</label>
<input
id="email"
type="email"
class="@error('email', 'login') is-invalid @enderror"
/>
@error('email', 'login')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
Blade позволяет вам добавлять содержимое к именованным стекам, которые можно отобразить где-нибудь еще в другом шаблоне или макете. Это может быть особенно полезно для указания любых библиотек JavaScript, необходимых для ваших дочерних шаблонов:
@push('scripts')
<script src="/example.js"></script>
@endpush
Если вы хотите добавить содержимое с помощью директивы @push
, только в том случае, если заданное логическое выражение возвращает true
, вы можете использовать директиву @pushIf
. Ниже приведен пример использования:
@pushIf($shouldPush, 'scripts')
<script src="/example.js"></script>
@endPushIf
Вы можете помещать в стек сколько угодно раз. Чтобы отобразить полное содержимое стека, передайте имя стека в директиву @stack
:
<head>
<!-- Содержание главы -->
@stack('scripts')
</head>
Если вы хотите добавить содержимое в начало стека, вы должны использовать директиву @prepend
:
@push('scripts')
Это будет второй...
@endpush
// Позже...
@prepend('scripts')
Это будет первое...
@endprepend
Директива @inject
используется для извлечения службы из контейнера служб Laravel. Первый аргумент, переданный в @inject
, – это имя переменной, в которую будет помещена служба. Второй аргумент – это имя класса или интерфейса службы, которую вы хотите извлечь:
@inject('metrics', 'App\Services\MetricsService')
<div>
Ежемесячный доход: {{ $metrics->monthlyRevenue() }}.
</div>
Иногда вам может потребоваться преобразовать сырую строку шаблона Blade в допустимый HTML. Вы можете сделать это, используя метод render
, предоставляемый фасадом Blade
. Метод render
принимает строку шаблона Blade и необязательный массив данных, которые будут переданы в шаблон:
use Illuminate\Support\Facades\Blade;
return Blade::render('Привет, {{ $name }}', ['name' => 'Джулиан Башир']);
Laravel рендерит встроенные шаблоны Blade, записывая их в директорию storage/framework/views
. Если вы хотите, чтобы Laravel удалял эти временные файлы после рендеринга шаблона Blade, вы можете передать аргумент deleteCachedView
методу:
return Blade::render(
'Привет, {{ $name }}',
['name' => 'Джулиан Башир'],
deleteCachedView: true
);
При использовании фронтенд фреймворков, таких как Turbo и htmx, иногда вам может потребоваться вернуть только часть шаблона Blade в HTTP-ответе. Фрагменты Blade позволяют вам сделать это. Для начала поместите часть вашего шаблона Blade между директивами @fragment
и @endfragment
:
@fragment('user-list')
<ul>
@foreach ($users as $user)
<li>{{ $user->name }}</li>
@endforeach
</ul>
@endfragment
Затем, при рендеринге представления, которое использует этот шаблон, вы можете вызвать метод fragment
, чтобы указать, что в исходящем HTTP-ответе должен быть включен только указанный фрагмент:
return view('dashboard', ['users' => $users])->fragment('user-list');
Метод fragmentIf
позволяет условно возвращать фрагмент представления на основе заданного условия. В противном случае будет возвращено целое представление:
return view('dashboard', ['users' => $users])
->fragmentIf($request->hasHeader('HX-Request'), 'user-list');
Методы fragments
и fragmentsIf
позволяют возвращать несколько фрагментов представления в ответе. Фрагменты будут объединены в одну строку:
view('dashboard', ['users' => $users])
->fragments(['user-list', 'comment-list']);
view('dashboard', ['users' => $users])
->fragmentsIf(
$request->hasHeader('HX-Request'),
['user-list', 'comment-list']
);
Blade позволяет вам определять ваши собственные пользовательские директивы с помощью метода directive
. Когда компилятор Blade встречает вашу директиву, он вызывает указанное замыкание с выражением, содержащимся в директиве.
В следующем примере создается директива @datetime($var)
, которая форматирует переданный $var
, который должен быть экземпляром DateTime
:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Регистрация любых служб приложения.
*/
public function register(): void
{
// ...
}
/**
* Загрузка любых служб приложения.
*/
public function boot(): void
{
Blade::directive('datetime', function (string $expression) {
return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
});
}
}
Как видите, мы привяжем метод format
к любому выражению, переданному в директиву. Итак, в этом примере окончательный PHP, сгенерированный этой директивой, будет:
<?php echo ($var)->format('m/d/Y H:i'); ?>
Warning
После обновления логики директивы Blade вам нужно будет удалить все кешированные шаблоны Blade. Кешированные шаблоны Blade могут быть удалены с помощью команды view:clear
Artisan.
Если вы попытаетесь вывести объект при помощи Blade, у объекта будет вызван метод __toString
. Метод __toString
является одним из встроенных "магических методов" PHP. Однако иногда вы не можете контролировать метод __toString
данного класса, например, когда класс, с которым вы взаимодействуете, принадлежит сторонней библиотеке.
В этих случаях Blade позволяет зарегистрировать пользовательский обработчик вывода для данного типа объектов. Для этого необходимо вызвать метод Blade stringable
. Метод stringable
принимает функцию, которая в аргументе принимает тип объекта, за рендеринг которого она отвечает. Обычно метод stringable
следует вызывать в методе boot
класса AppServiceProvider
вашего приложения:
use Illuminate\Support\Facades\Blade;
use Money\Money;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Blade::stringable(function (Money $money) {
return $money->formatTo('en_GB');
});
}
Теперь вы можете просто "вывести" экземпляр класса Money в шаблоне:
Стоимость: {{ $money }}
Программирование пользовательской директивы иногда бывает более сложным, чем необходимо при определении простых пользовательских условных операторов. По этой причине Blade содержит метод Blade::if
, который позволяет быстро определять пользовательские условные директивы с помощью замыканий. Например, давайте определим условие, которое проверяет настроенный по умолчанию «диск» приложения. Мы можем сделать это в методе boot
нашего AppServiceProvider
:
use Illuminate\Support\Facades\Blade;
/**
* Загрузка любых служб приложения.
*/
public function boot(): void
{
Blade::if('disk', function (string $value) {
return config('filesystems.default') === $value;
});
}
После того как пользовательское условие было определено, вы можете использовать его в своих шаблонах:
@disk('local')
<!-- Приложение использует локальный диск... -->
@elsedisk('s3')
<!-- Приложение использует диск s3... -->
@else
<!-- Приложение использует какой-то другой диск... -->
@enddisk
@unlessdisk('local')
<!-- Приложение не использует локальный диск... -->
@enddisk