Шаблони Blade
- Вступ
- Відображення даних
- Директиви Blade
- Компоненти
- Анонімні компоненти
- Створення макетів
- Форми
- Стеки
- Ін'єкція сервісів
- Відображення Вбудованих Шаблонів Blade
- Відображення фрагментів Blade
- Розширення Blade
Вступ
Blade - це простий, але потужний механізм шаблонів, який входить до складу Laravel. На відміну від деяких PHP механізмів шаблонів, Blade не обмежує вас у використанні звичайного PHP коду у ваших шаблонах. Насправді, всі шаблони Blade компілюються у звичайний PHP код і кешуються до тих пір, поки вони не будуть змінені, що означає, що Blade фактично не додає жодного навантаження на ваш застосунок. Файли шаблонів Blade використовують розширення .blade.php і зазвичай зберігаються в директорії resources/views.
Представлення Blade можуть бути повернені з маршрутів або контролерів за допомогою глобального хелпера view. Звичайно, як зазначено в документації про представлення, дані можуть бути передані до представлення Blade за допомогою другого аргументу хелпера view:
Route::get('/', function () {
return view('greeting', ['name' => 'Finn']);
});
Покращення Blade за допомогою Livewire
Бажаєте вивести ваші шаблони Blade на новий рівень і легко створювати динамічні інтерфейси? Перегляньте Laravel Livewire. Livewire дозволяє писати компоненти Blade, які доповнені динамічною функціональністю, що зазвичай можливо лише за допомогою фронтенд-фреймворків, таких як React або Vue, надаючи чудовий підхід до створення сучасних, реактивних фронтендів без складнощів, рендерингу на стороні клієнта або етапів збірки багатьох JavaScript-фреймворків.
Відображення даних
Ви можете відобразити дані, які передаються у ваші Blade представлення, обгорнувши змінну у фігурні дужки. Наприклад, враховуючи наступний маршрут:
Route::get('/', function () {
return view('welcome', ['name' => 'Samantha']);
});
Ви можете відобразити вміст змінної name таким чином:
Hello, {{ $name }}.
echo-вирази Blade {{ }} автоматично проходять через функцію PHP htmlspecialchars для запобігання XSS-атакам.
Ви не обмежені відображенням вмісту змінних, переданих у представлення. Ви також можете виводити результати будь-якої PHP-функції. Насправді, ви можете вставити будь-який PHP-код, який забажаєте, всередину виразу Blade для виводу:
The current UNIX timestamp is {{ time() }}.
Кодування HTML сутностей
За замовчуванням 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 {{ }} автоматично проходять через функцію PHP htmlspecialchars для запобігання XSS-атакам. Якщо ви не хочете, щоб ваші дані екранувалися, ви можете використовувати наступний синтаксис:
Hello, {!! $name !!}.
Будьте дуже обережні при виведенні контенту, що надається користувачами вашого застосунку. Зазвичай слід використовувати екранований синтаксис з подвійними фігурними дужками, щоб запобігти XSS-атакам при відображенні даних, наданих користувачами.
Blade і JavaScript фреймворки
Оскільки багато JavaScript-фреймворків також використовують "фігурні" дужки для позначення виразу, який має бути відображений у браузері, ви можете використовувати символ @, щоб повідомити механізму рендерингу Blade, що вираз має залишитися незмінним. Наприклад:
<h1>Laravel</h1>
Hello, @{{ name }}.
У цьому прикладі символ @ буде видалено Blade; однак, вираз {{ name }} залишиться незмінним для Blade-двигуна, що дозволить його відобразити вашим JavaScript-фреймворком.
Символ @ також може бути використаний для екранування директив Blade:
{{-- Blade шаблон --}} @@if() <!-- HTML вивід --> @if()
Відображення JSON
Іноді ви можете передати масив до вашого представлення з наміром відобразити його як JSON для ініціалізації змінної JavaScript. Наприклад:
<script>
var app = <?php echo json_encode($array); ?>;
</script>
Однак, замість того, щоб вручну викликати json_encode, ви можете використовувати директиву методу Illuminate\Support\Js::from. Метод from приймає ті ж аргументи, що й функція PHP json_encode; однак, він забезпечить, що отриманий JSON буде належним чином екранований для включення в HTML лапки. Метод from поверне рядок JSON.parse JavaScript вираз, який перетворить даний об'єкт або масив у дійсний JavaScript об'єкт:
<script>
var app = {{ Illuminate\Support\Js::from($array) }};
</script>
Останні версії каркасу застосунку Laravel включають фасад Js, який забезпечує зручний доступ до цієї функціональності у ваших шаблонах Blade:
<script>
var app = {{ Js::from($array) }};
</script>
Ви повинні використовувати метод Js::from лише для рендерингу існуючих змінних як JSON. Шаблонізація Blade базується на регулярних виразах, і спроби передати складний вираз у директиву можуть спричинити несподівані збої.
Директива @verbatim
Якщо ви відображаєте змінні JavaScript у великій частині вашого шаблону, ви можете обгорнути HTML у директиву @verbatim, щоб вам не довелося додавати префікс до кожного виразу Blade з символом @:
@verbatim
<div class="container">
Hello, {{ name }}.
</div>
@endverbatim
Blade Директиви
Крім успадкування шаблонів та відображення даних, Blade також надає зручні скорочення для загальних структур керування PHP, таких як умовні оператори та цикли. Ці скорочення забезпечують дуже чистий, лаконічний спосіб роботи зі структурами керування PHP, залишаючись при цьому знайомими їхнім PHP-аналогам.
Оператори if
Ви можете створювати 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
Якщо потрібно, ви можете вказати guard автентифікації, який слід перевірити при використанні директив @auth та @guest:
@auth('admin')
// Користувач автентифікований...
@endauth
@guest('admin')
// Користувач не автентифікований...
@endguest
Директиви середовища
Ви можете перевірити, чи застосунок працює в середовищі production, використовуючи директиву @production:
@production // Вміст, специфічний для продакшену... @endproduction
Або ви можете визначити, чи працює застосунок у певному середовищі, використовуючи директиву @env:
@env('staging')
// Застосунок працює в "staging"...
@endenv
@env(['staging', 'production'])
// Застосунок працює в режимі "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) Перший випадок... @break @case(2) Другий випадок... @break @default Випадок за замовчуванням... @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
Під час ітерації через цикл 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 |
The index of the current loop iteration (starts at 0). |
$loop->iteration |
The current loop iteration (starts at 1). |
$loop->remaining |
The iterations remaining in the loop. |
$loop->count |
The total number of items in the array being iterated. |
$loop->first |
Whether this is the first iteration through the loop. |
$loop->last |
Whether this is the last iteration through the loop. |
$loop->even |
Whether this is an even iteration through the loop. |
$loop->odd |
Whether this is an odd iteration through the loop. |
$loop->depth |
The nesting level of the current loop. |
$loop->parent |
When in a nested loop, the parent's loop variable. |
Умовні Класи & Стилі
Директива @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 може бути використана для умовного додавання inline 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-вхідний елемент типу checkbox "відміченим". Ця директива виведе checked, якщо надана умова оцінюється як true:
<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())>Submit</button>
Більше того, директива @readonly може бути використана для вказівки, чи повинен даний елемент бути "readonly":
<input
type="email"
name="email"
value="example@example.com"
@readonly($user->isNotAdmin())
/>
Крім того, директива @required може бути використана для вказівки, чи повинен даний елемент бути "обов'язковим":
<input
type="text"
name="title"
value="title"
@required($user->isAdmin())
/>
Включення підпредставлень
Ви можете вільно використовувати директиву @include, але Blade компоненти надають подібну функціональність і пропонують кілька переваг над директивою @include, таких як прив'язка даних і атрибутів.
Директива Blade @include дозволяє включити Blade представлення всередині іншого представлення. Всі змінні, які доступні в батьківському представленні, будуть доступні у включеному представленні:
<div>
@include('shared.errors')
<form>
<!-- Form Contents -->
</form>
</div>
Хоча включене представлення успадкує всі дані, доступні в батьківському представленні, ви також можете передати масив додаткових даних, які повинні бути доступні у включеному представленні:
@include('view.name', ['status' => 'complete'])
Якщо ви намагаєтеся @include представлення, яке не існує, Laravel видасть помилку. Якщо ви хочете включити представлення, яке може бути присутнім або відсутнім, вам слід використовувати директиву @includeIf:
@includeIf('view.name', ['status' => 'complete'])
Якщо ви хочете @include представлення, якщо заданий булевий вираз оцінюється як true або false, ви можете використовувати директиви @includeWhen та @includeUnless:
@includeWhen($boolean, 'view.name', ['status' => 'complete'])
@includeUnless($boolean, 'view.name', ['status' => 'complete'])
Щоб включити перше представлення, яке існує з заданого масиву представлень, ви можете використовувати директиву includeFirst:
@includeFirst(['custom.admin', 'admin'], ['status' => 'complete'])
Ви повинні уникати використання констант __DIR__ та __FILE__ у ваших Blade представленнях, оскільки вони будуть посилатися на місце розташування кешованого, скомпільованого представлення.
Відображення Представлень для Колекцій
Ви можете об'єднати цикли та включення в один рядок за допомогою директиви Blade @each:
@each('view.name', $jobs, 'job')
Першим аргументом директиви @each є представлення, яке потрібно відобразити для кожного елемента в масиві або колекції. Другим аргументом є масив або колекція, яку ви бажаєте перебрати, а третім аргументом є ім'я змінної, яке буде призначено поточній ітерації в межах представлення. Отже, наприклад, якщо ви перебираєте масив jobs, зазвичай ви захочете отримати доступ до кожної роботи як змінної job у межах представлення. Ключ масиву для поточної ітерації буде доступний як змінна key у межах представлення.
Ви також можете передати четвертий аргумент в директиву @each. Цей аргумент визначає представлення, яке буде відображено, якщо даний масив порожній.
@each('view.name', $jobs, 'job', 'view.empty')
Представлення, відображені за допомогою @each, не успадковують змінні з батьківського представлення. Якщо дочірнє представлення потребує цих змінних, слід використовувати директиви @foreach та @include.
Директива @once
The @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 у вашому шаблоні:
@php
$counter = 1;
@endphp
Або, якщо вам потрібно лише використовувати PHP для імпорту класу, ви можете скористатися директивою @use:
@use('App\Models\Flight')
Другий аргумент може бути наданий директиві @use для створення псевдоніма імпортованого класу:
@use('App\Models\Flight', 'FlightModel')
Якщо у вас є декілька класів в одному просторі імен, ви можете згрупувати імпорт цих класів:
@use('App\Models\{Flight, Airport}')
Директива @use також підтримує імпорт PHP функцій і констант, додаючи префікс до шляху імпорту за допомогою модифікаторів function або const:
@use(function App\Helpers\format_currency)
@use(const App\Constants\MAX_ATTEMPTS)
Так само, як і імпорт класів, для функцій та констант також підтримуються псевдоніми:
@use(function App\Helpers\format_currency, 'formatMoney')
@use(const App\Constants\MAX_ATTEMPTS, 'MAX_TRIES')
Груповані імпорти також підтримуються з обома модифікаторами function і const, що дозволяє імпортувати кілька символів з одного простору імен в одній директиві:
@use(function App\Helpers\{format_currency, format_date})
@use(const App\Constants\{MAX_ATTEMPTS, DEFAULT_TIMEOUT})
Коментарі
Blade також дозволяє визначати коментарі у ваших представленнях. Однак, на відміну від HTML-коментарів, коментарі Blade не включаються в HTML, що повертається вашим застосунком:
{{-- Цей коментар не буде присутній у згенерованому HTML --}}
Компоненти
Компоненти та слоти надають подібні переваги до секцій, макетів та включень; однак, деякі можуть вважати, що ментальна модель компонентів та слотів легша для розуміння. Існує два підходи до написання компонентів: компоненти на основі класів та анонімні компоненти.
Щоб створити компонент на основі класу, ви можете використовувати команду Artisan make:component. Щоб проілюструвати, як використовувати компоненти, ми створимо простий компонент 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'); }
Це дозволить використовувати компоненти пакета за їх простором імен постачальника, використовуючи синтаксис package-name:::
<x-nightshade::calendar />
<x-nightshade::color-picker />
Blade автоматично визначить клас, пов'язаний з цим компонентом, перетворивши ім'я компонента у PascalCase. Підкаталоги також підтримуються за допомогою нотації "крапка".
Відображення Компонентів
Щоб відобразити компонент, ви можете використовувати тег компонента Blade у одному з ваших шаблонів Blade. Теги компонентів Blade починаються зі строки x-, за якою слідує назва класу компонента в kebab case:
<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, тоді як kebab-case слід використовувати при посиланні на імена аргументів у ваших HTML-атрибутах. Наприклад, враховуючи наступний конструктор компонента:
/**
* Створіть екземпляр компонента.
*/
public function __construct(
public string $alertType,
) {}
Аргумент $alertType може бути переданий компоненту таким чином:
<x-alert alert-type="danger" />
Короткий синтаксис атрибутів
Коли передаєте атрибути до компонентів, ви також можете використовувати синтаксис "коротких атрибутів". Це часто зручно, оскільки імена атрибутів часто відповідають іменам змінних, до яких вони відносяться:
{{-- Short attribute syntax... --}}
<x-profile :$userId :$name />
{{-- Is equivalent to... --}}
<x-profile :user-id="$userId" :name="$name" />
Екранування Відображення Атрибутів
Оскільки деякі JavaScript-фреймворки, такі як Alpine.js, також використовують атрибути з префіксом двокрапки, ви можете використовувати подвійний префікс двокрапки (::), щоб повідомити Blade, що атрибут не є PHP-виразом. Наприклад, враховуючи наступний компонент:
<x-button ::class="{ danger: isDeleting }">
Submit
</x-button>
Наступний HTML буде відображено за допомогою Blade:
<button :class="{ danger: isDeleting }">
Submit
</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 }}>Components content</div>';
};
}
Замикання, яке повертається методом render вашого компонента, також може отримувати масив $data як єдиний аргумент. Цей масив міститиме кілька елементів, що надають інформацію про компонент:
return function (array $data) {
// $data['componentName'];
// $data['attributes'];
// $data['slot'];
return '<div {{ $attributes }}>Components content</div>';
}
Елементи в масиві $data ніколи не повинні бути безпосередньо вбудовані в рядок Blade, що повертається вашим методом render, оскільки це може дозволити виконання віддаленого коду через шкідливий вміст атрибутів.
Елемент componentName дорівнює імені, яке використовується в HTML-тегу після префіксу x-. Отже, <x-alert />'s componentName буде 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>
Використання директив, таких як @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>
Додавання класів за умовою
Іноді ви можете захотіти об'єднати класи, якщо задана умова є true. Ви можете досягти цього за допомогою методу class, який приймає масив класів, де ключ масиву містить клас або класи, які ви хочете додати, а значення є булевим виразом. Якщо елемент масиву має числовий ключ, він завжди буде включений у відображений список класів:
<div {{ $attributes->class(['p-4', 'bg-red' => $hasError]) }}>
{{ $message }}
</div>
Якщо вам потрібно об'єднати інші атрибути з вашим компонентом, ви можете приєднати метод merge до методу class:
<button {{ $attributes->class(['p-4'])->merge(['type' => 'button']) }}>
{{ $slot }}
</button>
Якщо вам потрібно умовно компілювати класи на інших HTML-елементах, які не повинні отримувати об'єднані атрибути, ви можете використовувати директиву @class.
Злиття Атрибутів Без Класу
Коли об'єднуються атрибути, які не є атрибутами 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') }}
Метод only може бути використаний для отримання лише атрибутів з вказаними ключами:
{{ $attributes->only(['class']) }}
Метод except може бути використаний для отримання всіх атрибутів, окрім тих, що мають задані ключі:
{{ $attributes->except(['class']) }}
Зарезервовані ключові слова
За замовчуванням деякі ключові слова зарезервовані для внутрішнього використання Blade з метою рендерингу компонентів. Наступні ключові слова не можуть бути визначені як публічні властивості або імена методів у ваших компонентах:
datarenderresolveViewshouldRenderviewwithAttributeswithName
Слоти
Ви часто будете потребувати передавати додатковий вміст до вашого компонента через "слоти". Слоти компонентів відображаються шляхом виведення змінної $slot. Щоб дослідити цю концепцію, уявімо, що компонент alert має наступну розмітку:
<!-- /resources/views/components/alert.blade.php -->
<div class="alert alert-danger">
{{ $slot }}
</div>
Ми можемо передати вміст до slot, вставляючи вміст у компонент:
<x-alert>
<strong>Whoops!</strong> Something went wrong!
</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> Server Error </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
Слоти (Scoped slots)
Якщо ви використовували JavaScript-фреймворк, такий як Vue, ви можете бути знайомі з "scoped slots", які дозволяють отримувати доступ до даних або методів з компонента всередині вашого слота. Ви можете досягти подібної поведінки в Laravel, визначивши публічні методи або властивості у вашому компоненті та отримуючи доступ до компонента всередині вашого слота через змінну $component. У цьому прикладі ми припустимо, що компонент x-alert має публічний метод formatAlert, визначений у класі його компонента:
<x-alert> <x-slot:title> {{ $component->formatAlert('Server Error') }} </x-slot> <strong>Упс!</strong> Щось пішло не так! </x-alert>
Атрибути Слота
Як і компоненти Blade, ви можете призначати додаткові атрибути слотам, такі як імена класів 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>
Щоб взаємодіяти з атрибутами слота, ви можете отримати доступ до властивості 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
Динамічні компоненти
Іноді вам може знадобитися відобразити компонент, але ви не знаєте, який компонент слід відобразити до моменту виконання. У цій ситуації ви можете використовувати вбудований компонент Laravel dynamic-component для відображення компонента на основі значення або змінної під час виконання:
// $componentName = "secondary-button";
<x-dynamic-component :component="$componentName" class="mt-4" />
Ручна Реєстрація Компонентів
Наступна документація щодо ручної реєстрації компонентів в основному стосується тих, хто пише пакети 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 автоматично визначить клас, пов'язаний з цим компонентом, перетворивши ім'я компонента у PascalCase. Підкаталоги також підтримуються за допомогою нотації "крапка".
Анонімні Компоненти
Подібно до вбудованих компонентів, анонімні компоненти надають механізм для керування компонентом через один файл. Однак, анонімні компоненти використовують один файл представлення і не мають пов'язаної класу. Щоб визначити анонімний компонент, вам потрібно лише розмістити шаблон Blade у вашій директорії resources/views/components. Наприклад, припустимо, що ви визначили компонент у resources/views/components/alert.blade.php, ви можете просто відобразити його таким чином:
<x-alert/>
Ви можете використовувати символ ., щоб вказати, якщо компонент вкладений глибше всередині каталогу components. Наприклад, припустимо, що компонент визначено у resources/views/components/inputs/button.blade.php, ви можете відобразити його таким чином:
<x-inputs.button/>
Анонімні кореневі компоненти
Іноді, коли компонент складається з багатьох шаблонів Blade, ви можете захотіти згрупувати шаблони даного компонента в одній директорії. Наприклад, уявіть компонент "accordion" з наступною структурою директорій:
/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>
Директива @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 ?? 'Todo Manager' }}</title>
</head>
<body>
<h1>Todos</h1>
<hr/>
{{ $slot }}
</body>
</html>
Застосування компонента Layout
Після того як компонент 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>
Custom 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>App Name - @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', 'Page Title') @section('sidebar') @@parent <p>Це додається до головної бічної панелі.</p> @endsection @section('content') <p>Це мій основний вміст.</p> @endsection
У цьому прикладі секція sidebar використовує директиву @@parent для додавання (замість перезапису) контенту до бокової панелі макета. Директива @@parent буде замінена контентом макета, коли представлення буде відображено.
На відміну від попереднього прикладу, цей розділ sidebar закінчується @endsection замість @show. Директива @endsection лише визначить розділ, тоді як @show визначить і негайно виведе розділ.
Директива @yield також приймає значення за замовчуванням як свій другий параметр. Це значення буде відображено, якщо секція, що викликається, не визначена:
@yield('content', 'Default content')
Форми
Поле CSRF
Кожного разу, коли ви визначаєте HTML-форму у вашому застосунку, ви повинні включити приховане поле CSRF-токена у форму, щоб middleware захисту від CSRF міг перевірити запит. Ви можете використовувати директиву Blade @csrf для генерації поля токена:
<form method="POST" action="/profile">
@csrf
...
</form>
Поле Method
Оскільки HTML форми не можуть виконувати запити PUT, PATCH або DELETE, вам потрібно додати приховане поле _method для імітації цих HTTP-дієслів. Директива Blade @method може створити це поле для вас:
<form action="/foo/bar" method="POST">
@method('PUT')
...
</form>
Помилки валідації
Директива @error може бути використана для швидкої перевірки, чи існують повідомлення про помилки валідації для заданого атрибуту. В межах директиви @error ви можете вивести змінну $message для відображення повідомлення про помилку:
<!-- /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
Оскільки директива @error компілюється в оператор "if", ви можете використовувати директиву @else для відображення вмісту, коли для атрибута немає помилки:
<!-- /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"
/>
Ви можете передати ім'я конкретного error bag як другий параметр до директиви @error, щоб отримати повідомлення про помилки валідації на сторінках, що містять кілька форм:
<!-- /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
Стеки
Blade дозволяє додавати в іменовані стеки, які можуть бути відображені в іншому місці в іншому представленні або макеті. Це може бути особливо корисним для вказівки будь-яких бібліотек JavaScript, необхідних вашим дочірнім представленням:
@push('scripts')
<script src="/example.js"></script>
@endpush
Якщо ви хочете @push контент, якщо заданий булевий вираз оцінюється як true, ви можете використовувати директиву @pushIf:
@pushIf($shouldPush, 'scripts')
<script src="/example.js"></script>
@endPushIf
Ви можете додавати до стека стільки разів, скільки потрібно. Щоб відобразити вміст усього стека, передайте ім'я стека в директиву @stack:
<head> <!-- Head Контент --> @stack('scripts') </head>
Якщо ви хочете додати вміст на початок стеку, слід використовувати директиву @prepend:
@push('scripts') This will be first... @endpush // Пізніше... @prepend('scripts') Це буде першим... @endprepend
Ін'єкція сервісів
Директива @inject може бути використана для отримання сервісу з Сервіс-контейнера Laravel. Перший аргумент, переданий в @inject, це ім'я змінної, в яку буде поміщено сервіс, тоді як другий аргумент - це ім'я класу або інтерфейсу сервісу, який ви хочете вирішити:
@inject('metrics', 'App\Services\MetricsService')
<div>
Monthly Revenue: {{ $metrics->monthlyRevenue() }}.
</div>
Відображення Вбудованих Шаблонів Blade
Іноді вам може знадобитися перетворити сирий рядок шаблону Blade у дійсний HTML. Ви можете досягти цього, використовуючи метод render, наданий фасадом Blade. Метод render приймає рядок шаблону Blade та необов'язковий масив даних для надання шаблону:
use Illuminate\Support\Facades\Blade;
return Blade::render('Hello, {{ $name }}', ['name' => 'Julian Bashir']);
Laravel рендерить вбудовані шаблони Blade, записуючи їх у директорію storage/framework/views. Якщо ви хочете, щоб Laravel видаляв ці тимчасові файли після рендерингу шаблону Blade, ви можете надати аргумент deleteCachedView до методу:
return Blade::render(
'Hello, {{ $name }}',
['name' => 'Julian Bashir'],
deleteCachedView: true
);
Відображення фрагментів Blade
Коли ви використовуєте фронтенд-фреймворки, такі як 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
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'); ?>
Після оновлення логіки директиви Blade, вам потрібно буде видалити всі кешовані Blade представлення. Кешовані Blade представлення можуть бути видалені за допомогою команди Artisan view:clear.
Спеціальні обробники Echo
Якщо ви намагаєтеся "echo" об'єкт за допомогою Blade, буде викликано метод об'єкта __toString. Метод __toString є одним з вбудованих "магічних методів" PHP. Однак іноді ви можете не мати контролю над методом __toString певного класу, наприклад, коли клас, з яким ви взаємодієте, належить до сторонньої бібліотеки.
У цих випадках Blade дозволяє зареєструвати користувацький обробник для виводу для цього конкретного типу об'єкта. Щоб досягти цього, слід викликати метод Blade stringable. Метод stringable приймає замикання. Це замикання повинно мати тип-натяк на тип об'єкта, за рендеринг якого воно відповідає. Зазвичай метод stringable слід викликати в методі boot класу AppServiceProvider вашого застосунку:
use Illuminate\Support\Facades\Blade; use Money\Money; /** * Ініціалізувати будь-які сервіси застосунку. */ public function boot(): void { Blade::stringable(function (Money $money) { return $money->formatTo('en_GB'); }); }
Як тільки ваш обробник echo було визначено, ви можете просто вивести об'єкт у вашому шаблоні Blade:
Cost: {{ $money }}
Користувацькі If Висловлювання
Програмування власної директиви іноді є більш складним, ніж необхідно, коли визначаються прості, власні умовні оператори. З цієї причини 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
