跳到內容

Blade 模板

簡介

Blade 是 Laravel 內建的簡單而強大的模板引擎。與一些 PHP 模板引擎不同,Blade 不限制您在模板中使用純 PHP 程式碼。實際上,所有 Blade 模板都被編譯成純 PHP 程式碼並快取,直到它們被修改,這意味著 Blade 幾乎不會為您的應用程式增加額外負擔。Blade 模板檔案使用 .blade.php 副檔名,通常儲存在 resources/views 目錄中。

Blade 視圖可以從路由或控制器中使用全域 view 輔助函式返回。當然,正如在 視圖 文件中提到的,可以使用 view 輔助函式的第二個參數將資料傳遞到 Blade 視圖。

1Route::get('/', function () {
2 return view('greeting', ['name' => 'Finn']);
3});

使用 Livewire 強化 Blade

想要將您的 Blade 模板提升到新的層次,並輕鬆構建動態介面嗎?請查看 Laravel Livewire。Livewire 允許您編寫 Blade 組件,這些組件通過動態功能進行擴充,這些功能通常只能通過前端框架(如 React 或 Vue)實現,從而為構建現代、反應式前端提供了一種很好的方法,而無需許多 JavaScript 框架的複雜性、客戶端渲染或構建步驟。

顯示資料

您可以通過將變數包在花括號中來顯示傳遞到 Blade 視圖的資料。例如,給定以下路由:

1Route::get('/', function () {
2 return view('welcome', ['name' => 'Samantha']);
3});

您可以像這樣顯示 name 變數的內容:

1Hello, {{ $name }}.

Blade 的 {{ }} echo 語句會自動通過 PHP 的 htmlspecialchars 函式發送,以防止 XSS 攻擊。

您不僅限於顯示傳遞到視圖的變數內容。您還可以 echo 任何 PHP 函式的結果。實際上,您可以將任何您想要的 PHP 程式碼放在 Blade echo 語句中:

1The current UNIX timestamp is {{ time() }}.

HTML 實體編碼

預設情況下,Blade(和 Laravel e 函式)將雙重編碼 HTML 實體。如果您想禁用雙重編碼,請從 AppServiceProviderboot 方法中調用 Blade::withoutDoubleEncoding 方法:

1<?php
2 
3namespace App\Providers;
4 
5use Illuminate\Support\Facades\Blade;
6use Illuminate\Support\ServiceProvider;
7 
8class AppServiceProvider extends ServiceProvider
9{
10 /**
11 * Bootstrap any application services.
12 */
13 public function boot(): void
14 {
15 Blade::withoutDoubleEncoding();
16 }
17}

顯示未轉義的資料

預設情況下,Blade {{ }} 語句會自動通過 PHP 的 htmlspecialchars 函式發送,以防止 XSS 攻擊。如果您不希望您的資料被轉義,您可以使用以下語法:

1Hello, {!! $name !!}.

當 echo 應用程式使用者提供的內容時,請務必小心。在顯示使用者提供的資料時,您通常應使用轉義的雙花括號語法來防止 XSS 攻擊。

Blade 與 JavaScript 框架

由於許多 JavaScript 框架也使用「花括號」來指示給定的表達式應在瀏覽器中顯示,因此您可以使用 @ 符號來告知 Blade 渲染引擎表達式應保持不變。例如:

1<h1>Laravel</h1>
2 
3Hello, @{{ name }}.

在此範例中,@ 符號將被 Blade 移除;但是,{{ name }} 表達式將保持 Blade 引擎不變,使其可以被您的 JavaScript 框架渲染。

@ 符號也可以用於轉義 Blade 指令:

1{{-- Blade template --}}
2@@if()
3 
4<!-- HTML output -->
5@if()

渲染 JSON

有時您可能會將陣列傳遞到視圖,目的是將其渲染為 JSON,以便初始化 JavaScript 變數。例如:

1<script>
2 var app = <?php echo json_encode($array); ?>;
3</script>

但是,您可以不用手動調用 json_encode,而是使用 Illuminate\Support\Js::from 方法指令。from 方法接受與 PHP 的 json_encode 函式相同的參數;但是,它將確保生成的 JSON 被正確轉義,以便包含在 HTML 引號中。from 方法將返回字串 JSON.parse JavaScript 語句,該語句會將給定的物件或陣列轉換為有效的 JavaScript 物件:

1<script>
2 var app = {{ Illuminate\Support\Js::from($array) }};
3</script>

最新版本的 Laravel 應用程式骨架包含一個 Js facade,它在您的 Blade 模板中提供了對此功能的便捷存取:

1<script>
2 var app = {{ Js::from($array) }};
3</script>

您應該僅使用 Js::from 方法將現有變數渲染為 JSON。Blade 模板基於正則表達式,嘗試將複雜表達式傳遞給指令可能會導致意外失敗。

@verbatim 指令

如果您在模板的很大一部分中顯示 JavaScript 變數,您可以將 HTML 包裹在 @verbatim 指令中,這樣您就不必為每個 Blade echo 語句添加 @ 符號:

1@verbatim
2 <div class="container">
3 Hello, {{ name }}.
4 </div>
5@endverbatim

Blade 指令

除了模板繼承和顯示資料外,Blade 還為常見的 PHP 控制結構(例如條件語句和迴圈)提供了便捷的快捷方式。這些快捷方式提供了一種非常簡潔、簡明的方式來處理 PHP 控制結構,同時也與其 PHP 對應物保持熟悉。

If 語句

您可以使用 @if@elseif@else@endif 指令來建構 if 語句。這些指令的功能與其 PHP 對應物完全相同:

1@if (count($records) === 1)
2 I have one record!
3@elseif (count($records) > 1)
4 I have multiple records!
5@else
6 I don't have any records!
7@endif

為了方便起見,Blade 也提供了 @unless 指令:

1@unless (Auth::check())
2 You are not signed in.
3@endunless

除了已經討論的條件指令外,@isset@empty 指令可以用作其各自 PHP 函式的便捷快捷方式:

1@isset($records)
2 // $records is defined and is not null...
3@endisset
4 
5@empty($records)
6 // $records is "empty"...
7@endempty

身份驗證指令

@auth@guest 指令可用於快速判斷當前使用者是否已通過身份驗證或是訪客:

1@auth
2 // The user is authenticated...
3@endauth
4 
5@guest
6 // The user is not authenticated...
7@endguest

如果需要,您可以使用 @auth@guest 指令指定應檢查的身份驗證守衛:

1@auth('admin')
2 // The user is authenticated...
3@endauth
4 
5@guest('admin')
6 // The user is not authenticated...
7@endguest

環境指令

您可以使用 @production 指令檢查應用程式是否在生產環境中運行:

1@production
2 // Production specific content...
3@endproduction

或者,您可以使用 @env 指令確定應用程式是否在特定環境中運行:

1@env('staging')
2 // The application is running in "staging"...
3@endenv
4 
5@env(['staging', 'production'])
6 // The application is running in "staging" or "production"...
7@endenv

區段指令

您可以使用 @hasSection 指令確定模板繼承區段是否具有內容:

1@hasSection('navigation')
2 <div class="pull-right">
3 @yield('navigation')
4 </div>
5 
6 <div class="clearfix"></div>
7@endif

您可以使用 sectionMissing 指令來確定區段是否沒有內容:

1@sectionMissing('navigation')
2 <div class="pull-right">
3 @include('default-navigation')
4 </div>
5@endif

Session 指令

@session 指令可用於確定 session 值是否存在。如果 session 值存在,則將評估 @session@endsession 指令內的模板內容。在 @session 指令的內容中,您可以 echo $value 變數以顯示 session 值:

1@session('status')
2 <div class="p-4 bg-green-100">
3 {{ $value }}
4 </div>
5@endsession

Switch 語句

可以使用 @switch@case@break@default@endswitch 指令來建構 Switch 語句:

1@switch($i)
2 @case(1)
3 First case...
4 @break
5 
6 @case(2)
7 Second case...
8 @break
9 
10 @default
11 Default case...
12@endswitch

迴圈

除了條件語句外,Blade 還提供了用於處理 PHP 迴圈結構的簡單指令。同樣,這些指令中的每一個的功能都與其 PHP 對應物完全相同:

1@for ($i = 0; $i < 10; $i++)
2 The current value is {{ $i }}
3@endfor
4 
5@foreach ($users as $user)
6 <p>This is user {{ $user->id }}</p>
7@endforeach
8 
9@forelse ($users as $user)
10 <li>{{ $user->name }}</li>
11@empty
12 <p>No users</p>
13@endforelse
14 
15@while (true)
16 <p>I'm looping forever.</p>
17@endwhile

在迭代 foreach 迴圈時,您可以使用迴圈變數來獲取有關迴圈的寶貴資訊,例如您是否處於迴圈的第一次或最後一次迭代。

使用迴圈時,您也可以使用 @continue@break 指令跳過當前迭代或結束迴圈:

1@foreach ($users as $user)
2 @if ($user->type == 1)
3 @continue
4 @endif
5 
6 <li>{{ $user->name }}</li>
7 
8 @if ($user->number == 5)
9 @break
10 @endif
11@endforeach

您也可以在指令宣告中包含繼續或中斷條件:

1@foreach ($users as $user)
2 @continue($user->type == 1)
3 
4 <li>{{ $user->name }}</li>
5 
6 @break($user->number == 5)
7@endforeach

迴圈變數

在迭代 foreach 迴圈時,迴圈內將提供一個 $loop 變數。此變數提供對一些有用的資訊的存取,例如當前迴圈索引以及這是否是迴圈的第一次或最後一次迭代:

1@foreach ($users as $user)
2 @if ($loop->first)
3 This is the first iteration.
4 @endif
5 
6 @if ($loop->last)
7 This is the last iteration.
8 @endif
9 
10 <p>This is user {{ $user->id }}</p>
11@endforeach

如果您在巢狀迴圈中,您可以通過 parent 屬性存取父迴圈的 $loop 變數:

1@foreach ($users as $user)
2 @foreach ($user->posts as $post)
3 @if ($loop->parent->first)
4 This is the first iteration of the parent loop.
5 @endif
6 @endforeach
7@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 類別字串。該指令接受類別陣列,其中陣列鍵包含您要添加的類別或類別,而值是布林表達式。如果陣列元素具有數字鍵,它將始終包含在渲染的類別列表中:

1@php
2 $isActive = false;
3 $hasError = true;
4@endphp
5 
6<span @class([
7 'p-4',
8 'font-bold' => $isActive,
9 'text-gray-500' => ! $isActive,
10 'bg-red' => $hasError,
11])></span>
12 
13<span class="p-4 text-gray-500 bg-red"></span>

同樣,@style 指令可用於有條件地將內聯 CSS 樣式添加到 HTML 元素:

1@php
2 $isActive = true;
3@endphp
4 
5<span @style([
6 'background-color: red',
7 'font-weight: bold' => $isActive,
8])></span>
9 
10<span style="background-color: red; font-weight: bold;"></span>

額外屬性

為了方便起見,您可以使用 @checked 指令輕鬆指示給定的 HTML 核取方塊輸入是否為「已選取」。如果提供的條件評估為 true,則此指令將 echo checked

1<input
2 type="checkbox"
3 name="active"
4 value="active"
5 @checked(old('active', $user->active))
6/>

同樣,@selected 指令可用於指示給定的 select 選項是否應為「已選取」:

1<select name="version">
2 @foreach ($product->versions as $version)
3 <option value="{{ $version }}" @selected(old('version') == $version)>
4 {{ $version }}
5 </option>
6 @endforeach
7</select>

此外,@disabled 指令可用於指示給定的元素是否應為「已停用」:

1<button type="submit" @disabled($errors->isNotEmpty())>Submit</button>

此外,@readonly 指令可用於指示給定的元素是否應為「唯讀」:

1<input
2 type="email"
3 name="email"
5 @readonly($user->isNotAdmin())
6/>

另外,@required 指令可用於指示給定的元素是否應為「必填」:

1<input
2 type="text"
3 name="title"
4 value="title"
5 @required($user->isAdmin())
6/>

包含子視圖

雖然您可以自由使用 @include 指令,但 Blade 組件提供了類似的功能,並且比 @include 指令提供了多種優勢,例如資料和屬性綁定。

Blade 的 @include 指令允許您從另一個視圖中包含 Blade 視圖。父視圖可用的所有變數都將提供給包含的視圖:

1<div>
2 @include('shared.errors')
3 
4 <form>
5 <!-- Form Contents -->
6 </form>
7</div>

即使包含的視圖將繼承父視圖中可用的所有資料,您也可以傳遞應提供給包含視圖的其他資料陣列:

1@include('view.name', ['status' => 'complete'])

如果您嘗試 @include 不存在的視圖,Laravel 將拋出錯誤。如果您想包含可能存在也可能不存在的視圖,則應使用 @includeIf 指令:

1@includeIf('view.name', ['status' => 'complete'])

如果您想在給定的布林表達式評估為 truefalse@include 視圖,則可以使用 @includeWhen@includeUnless 指令:

1@includeWhen($boolean, 'view.name', ['status' => 'complete'])
2 
3@includeUnless($boolean, 'view.name', ['status' => 'complete'])

要包含給定視圖陣列中第一個存在的視圖,您可以使用 includeFirst 指令:

1@includeFirst(['custom.admin', 'admin'], ['status' => 'complete'])

您應該避免在 Blade 視圖中使用 __DIR____FILE__ 常數,因為它們將引用快取的已編譯視圖的位置。

渲染集合的視圖

您可以使用 Blade 的 @each 指令將迴圈和包含合併為一行:

1@each('view.name', $jobs, 'job')

@each 指令的第一個參數是要為陣列或集合中的每個元素渲染的視圖。第二個參數是您要迭代的陣列或集合,而第三個參數是將分配給視圖中當前迭代的變數名稱。因此,例如,如果您要迭代 jobs 陣列,通常您會希望在視圖中將每個 job 作為 job 變數存取。當前迭代的陣列鍵將作為視圖中的 key 變數提供。

您也可以將第四個參數傳遞給 @each 指令。此參數確定如果給定陣列為空時將渲染的視圖。

1@each('view.name', $jobs, 'job', 'view.empty')

通過 @each 渲染的視圖不會繼承父視圖中的變數。如果子視圖需要這些變數,則應改用 @foreach@include 指令。

@once 指令

@once 指令允許您定義模板的一部分,該部分在每個渲染週期中僅評估一次。這對於使用堆疊將給定的 JavaScript 推送到頁面的標頭中可能很有用。例如,如果您在迴圈中渲染給定的組件,您可能希望僅在第一次渲染組件時將 JavaScript 推送到標頭:

1@once
2 @push('scripts')
3 <script>
4 // Your custom JavaScript...
5 </script>
6 @endpush
7@endonce

由於 @once 指令通常與 @push@prepend 指令結合使用,因此為了您的方便,提供了 @pushOnce@prependOnce 指令:

1@pushOnce('scripts')
2 <script>
3 // Your custom JavaScript...
4 </script>
5@endPushOnce

原生 PHP

在某些情況下,將 PHP 程式碼嵌入到視圖中很有用。您可以使用 Blade @php 指令在模板中執行純 PHP 程式碼區塊:

1@php
2 $counter = 1;
3@endphp

或者,如果您只需要使用 PHP 導入類別,則可以使用 @use 指令:

1@use('App\Models\Flight')

可以為 @use 指令提供第二個參數,以別名導入的類別:

1@use('App\Models\Flight', 'FlightModel')

註解

Blade 還允許您在視圖中定義註解。但是,與 HTML 註解不同,Blade 註解不包含在應用程式返回的 HTML 中:

1{{-- This comment will not be present in the rendered HTML --}}

組件

組件和插槽提供與區段、版面配置和包含類似的優勢;但是,有些人可能會發現組件和插槽的心理模型更容易理解。編寫組件有兩種方法:基於類別的組件和匿名組件。

要創建基於類別的組件,您可以使用 make:component Artisan 命令。為了說明如何使用組件,我們將創建一個簡單的 Alert 組件。make:component 命令會將組件放置在 app/View/Components 目錄中:

1php artisan make:component Alert

make:component 命令還將為組件創建視圖模板。視圖將放置在 resources/views/components 目錄中。在為您自己的應用程式編寫組件時,組件會在 app/View/Components 目錄和 resources/views/components 目錄中自動發現,因此通常不需要進一步的組件註冊。

您也可以在子目錄中創建組件:

1php artisan make:component Forms/Input

上面的命令將在 app/View/Components/Forms 目錄中創建一個 Input 組件,並且視圖將放置在 resources/views/components/forms 目錄中。

如果您想創建匿名組件(僅具有 Blade 模板而沒有類別的組件),您可以在調用 make:component 命令時使用 --view 標誌:

1php artisan make:component forms.input --view

上面的命令將在 resources/views/components/forms/input.blade.php 創建一個 Blade 檔案,該檔案可以通過 <x-forms.input /> 渲染為組件。

手動註冊套件組件

在為您自己的應用程式編寫組件時,組件會在 app/View/Components 目錄和 resources/views/components 目錄中自動發現。

但是,如果您正在構建使用 Blade 組件的套件,則需要手動註冊組件類別及其 HTML 標籤別名。您通常應在套件服務提供者的 boot 方法中註冊組件:

1use Illuminate\Support\Facades\Blade;
2 
3/**
4 * Bootstrap your package's services.
5 */
6public function boot(): void
7{
8 Blade::component('package-alert', Alert::class);
9}

註冊組件後,可以使用其標籤別名進行渲染:

1<x-package-alert/>

或者,您可以使用 componentNamespace 方法按照慣例自動加載組件類別。例如,Nightshade 套件可能具有 CalendarColorPicker 組件,這些組件位於 Package\Views\Components 命名空間中:

1use Illuminate\Support\Facades\Blade;
2 
3/**
4 * Bootstrap your package's services.
5 */
6public function boot(): void
7{
8 Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
9}

這將允許通過其供應商命名空間使用套件組件,使用 package-name:: 語法:

1<x-nightshade::calendar />
2<x-nightshade::color-picker />

Blade 將通過 pascal-casing 組件名稱自動檢測鏈接到此組件的類別。也支持使用「點」表示法的子目錄。

渲染組件

要顯示組件,您可以在 Blade 模板之一中使用 Blade 組件標籤。Blade 組件標籤以字串 x- 開頭,後跟組件類別的烤肉串式名稱:

1<x-alert/>
2 
3<x-user-profile/>

如果組件類別嵌套在 app/View/Components 目錄的更深層次中,您可以使用 . 字元來指示目錄嵌套。例如,如果我們假設組件位於 app/View/Components/Inputs/Button.php,我們可以像這樣渲染它:

1<x-inputs.button/>

如果您想有條件地渲染組件,您可以在組件類別上定義 shouldRender 方法。如果 shouldRender 方法返回 false,則不會渲染組件:

1use Illuminate\Support\Str;
2 
3/**
4 * Whether the component should be rendered
5 */
6public function shouldRender(): bool
7{
8 return Str::length($this->message) > 0;
9}

索引組件

有時,組件是組件組的一部分,您可能希望將相關組件分組在單個目錄中。例如,想像一個具有以下類別結構的「卡片」組件:

1App\Views\Components\Card\Card
2App\Views\Components\Card\Header
3App\Views\Components\Card\Body

由於根 Card 組件嵌套在 Card 目錄中,您可能會期望您需要通過 <x-card.card> 渲染組件。但是,當組件的檔案名稱與組件目錄的名稱匹配時,Laravel 會自動假定該組件是「根」組件,並允許您在不重複目錄名稱的情況下渲染組件:

1<x-card>
2 <x-card.header>...</x-card.header>
3 <x-card.body>...</x-card.body>
4</x-card>

傳遞資料到組件

您可以使用 HTML 屬性將資料傳遞到 Blade 組件。可以使用簡單的 HTML 屬性字串將硬編碼的原始值傳遞到組件。PHP 表達式和變數應通過使用 : 字元作為前綴的屬性傳遞到組件:

1<x-alert type="error" :message="$message"/>

您應該在其類別建構函式中定義組件的所有資料屬性。組件上的所有公共屬性都將自動提供給組件的視圖。沒有必要從組件的 render 方法將資料傳遞到視圖:

1<?php
2 
3namespace App\View\Components;
4 
5use Illuminate\View\Component;
6use Illuminate\View\View;
7 
8class Alert extends Component
9{
10 /**
11 * Create the component instance.
12 */
13 public function __construct(
14 public string $type,
15 public string $message,
16 ) {}
17 
18 /**
19 * Get the view / contents that represent the component.
20 */
21 public function render(): View
22 {
23 return view('components.alert');
24 }
25}

渲染組件後,您可以通過 echo 變數名稱來顯示組件公共變數的內容:

1<div class="alert alert-{{ $type }}">
2 {{ $message }}
3</div>

大小寫

組件建構函式參數應使用 camelCase 指定,而在 HTML 屬性中引用參數名稱時應使用 kebab-case。例如,給定以下組件建構函式:

1/**
2 * Create the component instance.
3 */
4public function __construct(
5 public string $alertType,
6) {}

可以像這樣將 $alertType 參數提供給組件:

1<x-alert alert-type="danger" />

簡短屬性語法

將屬性傳遞給組件時,您也可以使用「簡短屬性」語法。這通常很方便,因為屬性名稱經常與它們對應的變數名稱匹配:

1{{-- Short attribute syntax... --}}
2<x-profile :$userId :$name />
3 
4{{-- Is equivalent to... --}}
5<x-profile :user-id="$userId" :name="$name" />

轉義屬性渲染

由於某些 JavaScript 框架(如 Alpine.js)也使用冒號前綴屬性,因此您可以使用雙冒號 (::) 前綴來告知 Blade 該屬性不是 PHP 表達式。例如,給定以下組件:

1<x-button ::class="{ danger: isDeleting }">
2 Submit
3</x-button>

以下 HTML 將由 Blade 渲染:

1<button :class="{ danger: isDeleting }">
2 Submit
3</button>

組件方法

除了組件模板可用的公共變數外,還可以調用組件上的任何公共方法。例如,想像一個具有 isSelected 方法的組件:

1/**
2 * Determine if the given option is the currently selected option.
3 */
4public function isSelected(string $option): bool
5{
6 return $option === $this->selected;
7}

您可以通過調用與方法名稱匹配的變數從組件模板中執行此方法:

1<option {{ $isSelected($value) ? 'selected' : '' }} value="{{ $value }}">
2 {{ $label }}
3</option>

在組件類別中存取屬性和插槽

Blade 組件還允許您在類別的 render 方法內存取組件名稱、屬性和插槽。但是,為了存取此資料,您應該從組件的 render 方法返回一個閉包:

1use Closure;
2 
3/**
4 * Get the view / contents that represent the component.
5 */
6public function render(): Closure
7{
8 return function () {
9 return '<div {{ $attributes }}>Components content</div>';
10 };
11}

組件的 render 方法返回的閉包也可以接收 $data 陣列作為其唯一參數。此陣列將包含多個元素,這些元素提供有關組件的資訊:

1return function (array $data) {
2 // $data['componentName'];
3 // $data['attributes'];
4 // $data['slot'];
5 
6 return '<div {{ $attributes }}>Components content</div>';
7}

$data 陣列中的元素絕不應直接嵌入到 render 方法返回的 Blade 字串中,因為這樣做可能會允許通過惡意屬性內容執行遠程程式碼。

componentName 等於在 x- 前綴後面的 HTML 標籤中使用的名稱。因此 <x-alert />componentName 將是 alertattributes 元素將包含 HTML 標籤上存在的所有屬性。slot 元素是一個 Illuminate\Support\HtmlString 實例,其中包含組件插槽的內容。

閉包應返回一個字串。如果返回的字串對應於現有的視圖,則將渲染該視圖;否則,返回的字串將被評估為內聯 Blade 視圖。

其他依賴項

如果您的組件需要來自 Laravel 服務容器的依賴項,您可以在任何組件的資料屬性之前列出它們,它們將由容器自動注入:

1use App\Services\AlertCreator;
2 
3/**
4 * Create the component instance.
5 */
6public function __construct(
7 public AlertCreator $creator,
8 public string $type,
9 public string $message,
10) {}

隱藏屬性 / 方法

如果您想阻止某些公共方法或屬性作為變數公開給組件模板,您可以將它們添加到組件上的 $except 陣列屬性中:

1<?php
2 
3namespace App\View\Components;
4 
5use Illuminate\View\Component;
6 
7class Alert extends Component
8{
9 /**
10 * The properties / methods that should not be exposed to the component template.
11 *
12 * @var array
13 */
14 protected $except = ['type'];
15 
16 /**
17 * Create the component instance.
18 */
19 public function __construct(
20 public string $type,
21 ) {}
22}

組件屬性

我們已經研究了如何將資料屬性傳遞給組件;但是,有時您可能需要指定其他 HTML 屬性,例如 class,這些屬性不是組件功能所需的資料的一部分。通常,您希望將這些其他屬性向下傳遞到組件模板的根元素。例如,想像一下我們要像這樣渲染一個 alert 組件:

1<x-alert type="error" :message="$message" class="mt-4"/>

不屬於組件建構函式的所有屬性都將自動添加到組件的「屬性包」中。此屬性包通過 $attributes 變數自動提供給組件。所有屬性都可以通過 echo 此變數在組件中渲染:

1<div {{ $attributes }}>
2 <!-- Component content -->
3</div>

目前不支援在組件標籤中使用 @env 等指令。例如,<x-alert :live="@env('production')"/> 將不會被編譯。

預設 / 合併屬性

有時您可能需要為屬性指定預設值,或將其他值合併到某些組件的屬性中。為實現此目的,您可以使用屬性包的 merge 方法。此方法對於定義一組應始終應用於組件的預設 CSS 類別特別有用:

1<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
2 {{ $message }}
3</div>

如果我們假設像這樣使用此組件:

1<x-alert type="error" :message="$message" class="mb-4"/>

組件的最終渲染 HTML 將如下所示:

1<div class="alert alert-error mb-4">
2 <!-- Contents of the $message variable -->
3</div>

有條件地合併類別

有時,您可能希望在給定條件為 true 時合併類別。您可以通過 class 方法實現此目的,該方法接受類別陣列,其中陣列鍵包含您要添加的類別或類別,而值是布林表達式。如果陣列元素具有數字鍵,它將始終包含在渲染的類別列表中:

1<div {{ $attributes->class(['p-4', 'bg-red' => $hasError]) }}>
2 {{ $message }}
3</div>

如果您需要將其他屬性合併到組件上,您可以將 merge 方法鏈接到 class 方法上:

1<button {{ $attributes->class(['p-4'])->merge(['type' => 'button']) }}>
2 {{ $slot }}
3</button>

如果您需要在不應接收合併屬性的其他 HTML 元素上有條件地編譯類別,則可以使用 @class 指令

非類別屬性合併

合併非 class 屬性的屬性時,提供給 merge 方法的值將被視為屬性的「預設」值。但是,與 class 屬性不同,這些屬性不會與注入的屬性值合併。相反,它們將被覆蓋。例如,button 組件的實現可能如下所示:

1<button {{ $attributes->merge(['type' => 'button']) }}>
2 {{ $slot }}
3</button>

要使用自訂 type 渲染 button 組件,可以在使用組件時指定它。如果未指定類型,則將使用 button 類型:

1<x-button type="submit">
2 Submit
3</x-button>

此範例中 button 組件的渲染 HTML 將是:

1<button type="submit">
2 Submit
3</button>

如果您希望除了 class 屬性之外的其他屬性也能將預設值和注入值合併在一起,您可以使用 prepends 方法。在此範例中,data-controller 屬性將始終以 profile-controller 開頭,任何額外注入的 data-controller 值將會放在此預設值之後

1<div {{ $attributes->merge(['data-controller' => $attributes->prepends('profile-controller')]) }}>
2 {{ $slot }}
3</div>

擷取和篩選屬性

您可以使用 filter 方法來篩選屬性。此方法接受一個閉包,如果您希望在屬性包中保留該屬性,則應傳回 true

1{{ $attributes->filter(fn (string $value, string $key) => $key == 'foo') }}

為了方便起見,您可以使用 whereStartsWith 方法來擷取所有鍵以給定字串開頭的屬性

1{{ $attributes->whereStartsWith('wire:model') }}

相反地,whereDoesntStartWith 方法可用於排除所有鍵以給定字串開頭的屬性

1{{ $attributes->whereDoesntStartWith('wire:model') }}

使用 first 方法,您可以呈現給定屬性包中的第一個屬性

1{{ $attributes->whereStartsWith('wire:model')->first() }}

如果您想檢查組件上是否存在某個屬性,您可以使用 has 方法。此方法接受屬性名稱作為其唯一參數,並傳回布林值,指示該屬性是否存在

1@if ($attributes->has('class'))
2 <div>Class attribute is present</div>
3@endif

如果將陣列傳遞給 has 方法,則該方法將判斷組件上是否同時存在所有給定的屬性

1@if ($attributes->has(['name', 'class']))
2 <div>All of the attributes are present</div>
3@endif

hasAny 方法可用於判斷組件上是否存在任何給定的屬性

1@if ($attributes->hasAny(['href', ':href', 'v-bind:href']))
2 <div>One of the attributes is present</div>
3@endif

您可以使用 get 方法來擷取特定屬性的值

1{{ $attributes->get('class') }}

保留關鍵字

預設情況下,某些關鍵字是 Blade 內部使用保留的,以便呈現組件。以下關鍵字不能在您的組件中定義為公有屬性或方法名稱

  • data
  • render
  • resolveView
  • shouldRender
  • view
  • withAttributes
  • withName

插槽

您通常需要透過「插槽」將額外的內容傳遞到您的組件。組件插槽是透過呼應 $slot 變數來呈現的。為了探索這個概念,讓我們想像一下,一個 alert 組件具有以下標記

1<!-- /resources/views/components/alert.blade.php -->
2 
3<div class="alert alert-danger">
4 {{ $slot }}
5</div>

我們可以透過將內容注入到組件中,將內容傳遞到 slot

1<x-alert>
2 <strong>Whoops!</strong> Something went wrong!
3</x-alert>

有時,組件可能需要在組件內的不同位置呈現多個不同的插槽。讓我們修改我們的警示組件,以允許注入「標題」插槽

1<!-- /resources/views/components/alert.blade.php -->
2 
3<span class="alert-title">{{ $title }}</span>
4 
5<div class="alert alert-danger">
6 {{ $slot }}
7</div>

您可以使用 x-slot 標籤來定義具名插槽的內容。任何不在明確 x-slot 標籤內的內容都將在 $slot 變數中傳遞到組件

1<x-alert>
2 <x-slot:title>
3 Server Error
4 </x-slot>
5 
6 <strong>Whoops!</strong> Something went wrong!
7</x-alert>

您可以調用插槽的 isEmpty 方法來判斷插槽是否包含內容

1<span class="alert-title">{{ $title }}</span>
2 
3<div class="alert alert-danger">
4 @if ($slot->isEmpty())
5 This is default content if the slot is empty.
6 @else
7 {{ $slot }}
8 @endif
9</div>

此外,hasActualContent 方法可用於判斷插槽是否包含任何不是 HTML 註解的「實際」內容

1@if ($slot->hasActualContent())
2 The scope has non-comment content.
3@endif

作用域插槽

如果您使用過像 Vue 這樣的 JavaScript 框架,您可能對「作用域插槽」很熟悉,它允許您從插槽內部的組件存取資料或方法。您可以在 Laravel 中透過在組件上定義公有方法或屬性,並透過 $component 變數在您的插槽中存取組件,來實現類似的行為。在此範例中,我們將假設 x-alert 組件在其組件類別上定義了一個公有 formatAlert 方法

1<x-alert>
2 <x-slot:title>
3 {{ $component->formatAlert('Server Error') }}
4 </x-slot>
5 
6 <strong>Whoops!</strong> Something went wrong!
7</x-alert>

插槽屬性

與 Blade 組件一樣,您可以將額外的屬性指派給插槽,例如 CSS 類別名稱

1<x-card class="shadow-sm">
2 <x-slot:heading class="font-bold">
3 Heading
4 </x-slot>
5 
6 Content
7 
8 <x-slot:footer class="text-sm">
9 Footer
10 </x-slot>
11</x-card>

若要與插槽屬性互動,您可以存取插槽變數的 attributes 屬性。有關如何與屬性互動的更多資訊,請查閱有關組件屬性的文件

1@props([
2 'heading',
3 'footer',
4])
5 
6<div {{ $attributes->class(['border']) }}>
7 <h1 {{ $heading->attributes->class(['text-lg']) }}>
8 {{ $heading }}
9 </h1>
10 
11 {{ $slot }}
12 
13 <footer {{ $footer->attributes->class(['text-gray-700']) }}>
14 {{ $footer }}
15 </footer>
16</div>

內聯組件視圖

對於非常小的組件,同時管理組件類別和組件的視圖範本可能會感到繁瑣。因此,您可以直接從 render 方法傳回組件的標記

1/**
2 * Get the view / contents that represent the component.
3 */
4public function render(): string
5{
6 return <<<'blade'
7 <div class="alert alert-danger">
8 {{ $slot }}
9 </div>
10 blade;
11}

產生內聯視圖組件

若要建立呈現內聯視圖的組件,您可以在執行 make:component 命令時使用 inline 選項

1php artisan make:component Alert --inline

動態組件

有時您可能需要呈現組件,但直到運行時才知道應該呈現哪個組件。在這種情況下,您可以使用 Laravel 內建的 dynamic-component 組件,根據運行時值或變數來呈現組件

1// $componentName = "secondary-button";
2 
3<x-dynamic-component :component="$componentName" class="mt-4" />

手動註冊組件

以下關於手動註冊組件的文件主要適用於那些正在編寫包含視圖組件的 Laravel 套件的人員。如果您沒有編寫套件,則組件文件的這一部分可能與您無關。

在為您自己的應用程式編寫組件時,組件會在 app/View/Components 目錄和 resources/views/components 目錄中自動發現。

但是,如果您正在構建使用 Blade 組件的套件,或將組件放置在非傳統目錄中,您將需要手動註冊您的組件類別及其 HTML 標籤別名,以便 Laravel 知道在哪裡找到組件。您通常應該在套件服務提供者的 boot 方法中註冊您的組件

1use Illuminate\Support\Facades\Blade;
2use VendorPackage\View\Components\AlertComponent;
3 
4/**
5 * Bootstrap your package's services.
6 */
7public function boot(): void
8{
9 Blade::component('package-alert', AlertComponent::class);
10}

註冊組件後,可以使用其標籤別名進行渲染:

1<x-package-alert/>

自動載入套件組件

或者,您可以使用 componentNamespace 方法按照慣例自動加載組件類別。例如,Nightshade 套件可能具有 CalendarColorPicker 組件,這些組件位於 Package\Views\Components 命名空間中:

1use Illuminate\Support\Facades\Blade;
2 
3/**
4 * Bootstrap your package's services.
5 */
6public function boot(): void
7{
8 Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
9}

這將允許通過其供應商命名空間使用套件組件,使用 package-name:: 語法:

1<x-nightshade::calendar />
2<x-nightshade::color-picker />

Blade 將通過 pascal-casing 組件名稱自動檢測鏈接到此組件的類別。也支持使用「點」表示法的子目錄。

匿名組件

與內聯組件類似,匿名組件提供了一種透過單個檔案管理組件的機制。但是,匿名組件使用單個視圖檔案,並且沒有關聯的類別。若要定義匿名組件,您只需要將 Blade 範本放置在您的 resources/views/components 目錄中。例如,假設您在 resources/views/components/alert.blade.php 中定義了一個組件,您可以像這樣簡單地呈現它

1<x-alert/>

您可以使用 . 字元來指示組件是否更深層地嵌套在 components 目錄內。例如,假設組件在 resources/views/components/inputs/button.blade.php 中定義,您可以像這樣呈現它

1<x-inputs.button/>

匿名索引組件

有時,當組件由許多 Blade 範本組成時,您可能希望將給定組件的範本分組在單個目錄中。例如,想像一個具有以下目錄結構的「accordion」組件

1/resources/views/components/accordion.blade.php
2/resources/views/components/accordion/item.blade.php

此目錄結構允許您像這樣呈現 accordion 組件及其項目

1<x-accordion>
2 <x-accordion.item>
3 ...
4 </x-accordion.item>
5</x-accordion>

但是,為了透過 x-accordion 呈現 accordion 組件,我們被迫將「index」accordion 組件範本放置在 resources/views/components 目錄中,而不是將其與其他 accordion 相關範本一起嵌套在 accordion 目錄中。

值得慶幸的是,Blade 允許您將與組件目錄名稱匹配的檔案放置在組件目錄本身內。當此範本存在時,即使它嵌套在目錄中,也可以將其呈現為組件的「根」元素。因此,我們可以繼續使用上面範例中給出的相同 Blade 語法;但是,我們將調整我們的目錄結構,如下所示

1/resources/views/components/accordion/accordion.blade.php
2/resources/views/components/accordion/item.blade.php

資料屬性 / 屬性

由於匿名組件沒有任何關聯的類別,您可能會想知道如何區分哪些資料應作為變數傳遞到組件,哪些屬性應放置在組件的屬性包中。

您可以使用組件 Blade 範本頂部的 @props 指令來指定哪些屬性應被視為資料變數。組件上的所有其他屬性都將透過組件的屬性包提供。如果您希望為資料變數提供預設值,您可以將變數的名稱指定為陣列鍵,將預設值指定為陣列值

1<!-- /resources/views/components/alert.blade.php -->
2 
3@props(['type' => 'info', 'message'])
4 
5<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
6 {{ $message }}
7</div>

給定上面的組件定義,我們可以像這樣呈現組件

1<x-alert type="error" :message="$message" class="mb-4"/>

存取父層資料

有時您可能想要從子組件內的父組件存取資料。在這些情況下,您可以使用 @aware 指令。例如,想像一下我們正在構建一個複雜的選單組件,該組件由父組件 <x-menu> 和子組件 <x-menu.item> 組成

1<x-menu color="purple">
2 <x-menu.item>...</x-menu.item>
3 <x-menu.item>...</x-menu.item>
4</x-menu>

<x-menu> 組件可能具有如下的實作

1<!-- /resources/views/components/menu/index.blade.php -->
2 
3@props(['color' => 'gray'])
4 
5<ul {{ $attributes->merge(['class' => 'bg-'.$color.'-200']) }}>
6 {{ $slot }}
7</ul>

由於 color 屬性僅傳遞到父組件 (<x-menu>),因此它在 <x-menu.item> 內部將不可用。但是,如果我們使用 @aware 指令,我們也可以使其在 <x-menu.item> 內部可用

1<!-- /resources/views/components/menu/item.blade.php -->
2 
3@aware(['color' => 'gray'])
4 
5<li {{ $attributes->merge(['class' => 'text-'.$color.'-800']) }}>
6 {{ $slot }}
7</li>

@aware 指令無法存取未透過 HTML 屬性明確傳遞到父組件的父資料。未明確傳遞到父組件的預設 @props 值無法由 @aware 指令存取。

匿名組件路徑

如前所述,匿名組件通常是透過將 Blade 範本放置在您的 resources/views/components 目錄中來定義的。但是,您偶爾可能想要向 Laravel 註冊其他匿名組件路徑,以補充預設路徑。

anonymousComponentPath 方法接受匿名組件位置的「路徑」作為其第一個參數,並接受組件應放置在其下的可選「命名空間」作為其第二個參數。通常,此方法應從您的應用程式服務提供者之一的 boot 方法中調用

1/**
2 * Bootstrap any application services.
3 */
4public function boot(): void
5{
6 Blade::anonymousComponentPath(__DIR__.'/../components');
7}

當組件路徑在沒有指定前綴的情況下註冊時(如上面的範例所示),它們也可以在您的 Blade 組件中呈現,而無需對應的前綴。例如,如果 panel.blade.php 組件存在於上面註冊的路徑中,則可以像這樣呈現它

1<x-panel />

前綴「命名空間」可以作為第二個參數提供給 anonymousComponentPath 方法

1Blade::anonymousComponentPath(__DIR__.'/../components', 'dashboard');

當提供前綴時,可以透過在呈現組件時將命名空間前綴到組件名稱來呈現該「命名空間」內的組件

1<x-dashboard::panel />

建立版面配置

使用組件的版面配置

大多數 Web 應用程式在各種頁面上都保持相同的通用佈局。如果我們必須在我們建立的每個視圖中重複整個佈局 HTML,那麼維護我們的應用程式將會非常繁瑣且難以維護。值得慶幸的是,將此佈局定義為單個Blade 組件,然後在整個應用程式中使用它很方便。

定義佈局組件

例如,想像一下我們正在構建一個「待辦事項」列表應用程式。我們可能會定義一個如下所示的 layout 組件

1<!-- resources/views/components/layout.blade.php -->
2 
3<html>
4 <head>
5 <title>{{ $title ?? 'Todo Manager' }}</title>
6 </head>
7 <body>
8 <h1>Todos</h1>
9 <hr/>
10 {{ $slot }}
11 </body>
12</html>

應用佈局組件

一旦定義了 layout 組件,我們就可以建立一個使用該組件的 Blade 視圖。在此範例中,我們將定義一個簡單的視圖來顯示我們的任務列表

1<!-- resources/views/tasks.blade.php -->
2 
3<x-layout>
4 @foreach ($tasks as $task)
5 <div>{{ $task }}</div>
6 @endforeach
7</x-layout>

請記住,注入到組件中的內容將提供給我們 layout 組件中的預設 $slot 變數。您可能已經注意到,如果提供了 $title 插槽,我們的 layout 也會尊重它;否則,將顯示預設標題。我們可以使用組件文件中討論的標準插槽語法,從我們的任務列表視圖中注入自訂標題

1<!-- resources/views/tasks.blade.php -->
2 
3<x-layout>
4 <x-slot:title>
5 Custom Title
6 </x-slot>
7 
8 @foreach ($tasks as $task)
9 <div>{{ $task }}</div>
10 @endforeach
11</x-layout>

現在我們已經定義了我們的佈局和任務列表視圖,我們只需要從路由傳回 task 視圖

1use App\Models\Task;
2 
3Route::get('/tasks', function () {
4 return view('tasks', ['tasks' => Task::all()]);
5});

使用模板繼承的版面配置

定義佈局

佈局也可以透過「範本繼承」來建立。這是引入組件之前構建應用程式的主要方式。

首先,讓我們看一個簡單的範例。首先,我們將檢視頁面佈局。由於大多數 Web 應用程式在各種頁面上都保持相同的通用佈局,因此將此佈局定義為單個 Blade 視圖非常方便

1<!-- resources/views/layouts/app.blade.php -->
2 
3<html>
4 <head>
5 <title>App Name - @yield('title')</title>
6 </head>
7 <body>
8 @section('sidebar')
9 This is the master sidebar.
10 @show
11 
12 <div class="container">
13 @yield('content')
14 </div>
15 </body>
16</html>

如您所見,此檔案包含典型的 HTML 標記。但是,請注意 @section@yield 指令。顧名思義,@section 指令定義內容區塊,而 @yield 指令用於顯示給定區塊的內容。

現在我們已經為我們的應用程式定義了一個佈局,讓我們定義一個繼承該佈局的子頁面。

擴展佈局

在定義子視圖時,請使用 @extends Blade 指令來指定子視圖應「繼承」哪個佈局。擴展 Blade 佈局的視圖可以使用 @section 指令將內容注入到佈局的區塊中。請記住,如上面的範例所示,這些區塊的內容將使用 @yield 顯示在佈局中

1<!-- resources/views/child.blade.php -->
2 
3@extends('layouts.app')
4 
5@section('title', 'Page Title')
6 
7@section('sidebar')
8 @@parent
9 
10 <p>This is appended to the master sidebar.</p>
11@endsection
12 
13@section('content')
14 <p>This is my body content.</p>
15@endsection

在此範例中,sidebar 區塊正在使用 @@parent 指令來附加(而不是覆寫)內容到佈局的側邊欄。當視圖呈現時,@@parent 指令將被佈局的內容取代。

與之前的範例相反,此 sidebar 區塊以 @endsection 而不是 @show 結尾。@endsection 指令僅定義一個區塊,而 @show 將定義並立即產生該區塊。

@yield 指令也接受一個預設值作為其第二個參數。如果正在產生的區塊未定義,則將呈現此值

1@yield('content', 'Default content')

表單

CSRF 欄位

每當您在應用程式中定義 HTML 表單時,您都應該在表單中包含一個隱藏的 CSRF 令牌欄位,以便CSRF 保護中間件可以驗證請求。您可以使用 @csrf Blade 指令來產生令牌欄位

1<form method="POST" action="/profile">
2 @csrf
3 
4 ...
5</form>

方法欄位

由於 HTML 表單無法發出 PUTPATCHDELETE 請求,因此您需要新增一個隱藏的 _method 欄位來欺騙這些 HTTP 動詞。@method Blade 指令可以為您建立此欄位

1<form action="/foo/bar" method="POST">
2 @method('PUT')
3 
4 ...
5</form>

驗證錯誤

@error 指令可用於快速檢查給定屬性是否存在驗證錯誤訊息。在 @error 指令中,您可以呼應 $message 變數來顯示錯誤訊息

1<!-- /resources/views/post/create.blade.php -->
2 
3<label for="title">Post Title</label>
4 
5<input
6 id="title"
7 type="text"
8 class="@error('title') is-invalid @enderror"
9/>
10 
11@error('title')
12 <div class="alert alert-danger">{{ $message }}</div>
13@enderror

由於 @error 指令會編譯為「if」語句,因此您可以使用 @else 指令在屬性沒有錯誤時呈現內容

1<!-- /resources/views/auth.blade.php -->
2 
3<label for="email">Email address</label>
4 
5<input
6 id="email"
7 type="email"
8 class="@error('email') is-invalid @else is-valid @enderror"
9/>

您可以將特定錯誤包的名稱作為第二個參數傳遞給 @error 指令,以檢索包含多個表單的頁面上的驗證錯誤訊息

1<!-- /resources/views/auth.blade.php -->
2 
3<label for="email">Email address</label>
4 
5<input
6 id="email"
7 type="email"
8 class="@error('email', 'login') is-invalid @enderror"
9/>
10 
11@error('email', 'login')
12 <div class="alert alert-danger">{{ $message }}</div>
13@enderror

堆疊

Blade 允許您推送到具名堆疊,這些堆疊可以在另一個視圖或佈局中的其他位置呈現。這對於指定您的子視圖所需的任何 JavaScript 庫特別有用

1@push('scripts')
2 <script src="/example.js"></script>
3@endpush

如果您想在給定的布林值運算式評估為 true@push 內容,您可以使用 @pushIf 指令

1@pushIf($shouldPush, 'scripts')
2 <script src="/example.js"></script>
3@endPushIf

您可以根據需要多次推送到堆疊。若要呈現完整的堆疊內容,請將堆疊的名稱傳遞給 @stack 指令

1<head>
2 <!-- Head Contents -->
3 
4 @stack('scripts')
5</head>

如果您想將內容添加到堆疊的開頭,則應使用 @prepend 指令

1@push('scripts')
2 This will be second...
3@endpush
4 
5// Later...
6 
7@prepend('scripts')
8 This will be first...
9@endprepend

服務注入

@inject 指令可用於從 Laravel 服務容器中檢索服務。傳遞給 @inject 的第一個參數是將放置服務的變數名稱,而第二個參數是您要解析的服務的類別或介面名稱

1@inject('metrics', 'App\Services\MetricsService')
2 
3<div>
4 Monthly Revenue: {{ $metrics->monthlyRevenue() }}.
5</div>

渲染內聯 Blade 模板

有時您可能需要將原始 Blade 範本字串轉換為有效的 HTML。您可以使用 Blade 外觀提供的 render 方法來完成此操作。render 方法接受 Blade 範本字串和一個可選的資料陣列,以提供給範本

1use Illuminate\Support\Facades\Blade;
2 
3return Blade::render('Hello, {{ $name }}', ['name' => 'Julian Bashir']);

Laravel 透過將內聯 Blade 範本寫入到 storage/framework/views 目錄來呈現它們。如果您希望 Laravel 在呈現 Blade 範本後刪除這些暫存檔案,您可以將 deleteCachedView 參數提供給方法

1return Blade::render(
2 'Hello, {{ $name }}',
3 ['name' => 'Julian Bashir'],
4 deleteCachedView: true
5);

渲染 Blade 片段

當使用前端框架(例如 Turbohtmx)時,您偶爾可能只需要在您的 HTTP 回應中傳回 Blade 範本的一部分。Blade 「片段」允許您做到這一點。首先,將您的 Blade 範本的一部分放置在 @fragment@endfragment 指令之間

1@fragment('user-list')
2 <ul>
3 @foreach ($users as $user)
4 <li>{{ $user->name }}</li>
5 @endforeach
6 </ul>
7@endfragment

然後,在呈現使用此範本的視圖時,您可以調用 fragment 方法來指定僅應將指定的片段包含在傳出的 HTTP 回應中

1return view('dashboard', ['users' => $users])->fragment('user-list');

fragmentIf 方法允許您根據給定條件有條件地傳回視圖的片段。否則,將傳回整個視圖

1return view('dashboard', ['users' => $users])
2 ->fragmentIf($request->hasHeader('HX-Request'), 'user-list');

fragmentsfragmentsIf 方法允許您在回應中傳回多個視圖片段。這些片段將連接在一起

1view('dashboard', ['users' => $users])
2 ->fragments(['user-list', 'comment-list']);
3 
4view('dashboard', ['users' => $users])
5 ->fragmentsIf(
6 $request->hasHeader('HX-Request'),
7 ['user-list', 'comment-list']
8 );

擴展 Blade

Blade 允許您使用 directive 方法定義您自己的自訂指令。當 Blade 編譯器遇到自訂指令時,它將使用指令包含的運算式調用提供的回調。

以下範例建立了一個 @datetime($var) 指令,該指令格式化給定的 $var,它應該是 DateTime 的實例

1<?php
2 
3namespace App\Providers;
4 
5use Illuminate\Support\Facades\Blade;
6use Illuminate\Support\ServiceProvider;
7 
8class AppServiceProvider extends ServiceProvider
9{
10 /**
11 * Register any application services.
12 */
13 public function register(): void
14 {
15 // ...
16 }
17 
18 /**
19 * Bootstrap any application services.
20 */
21 public function boot(): void
22 {
23 Blade::directive('datetime', function (string $expression) {
24 return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
25 });
26 }
27}

如您所見,我們將鏈式調用 format 方法到傳遞到指令的任何運算式。因此,在此範例中,此指令產生的最終 PHP 將是

1<?php echo ($var)->format('m/d/Y H:i'); ?>

更新 Blade 指令的邏輯後,您需要刪除所有快取的 Blade 視圖。可以使用 view:clear Artisan 命令刪除快取的 Blade 視圖。

自訂 Echo 處理器

如果您嘗試使用 Blade「呼應」一個物件,則將調用該物件的 __toString 方法。__toString 方法是 PHP 的內建「魔術方法」之一。但是,有時您可能無法控制給定類別的 __toString 方法,例如當您正在互動的類別屬於第三方庫時。

在這些情況下,Blade 允許您為該特定物件類型註冊自訂呼應處理程序。若要完成此操作,您應該調用 Blade 的 stringable 方法。stringable 方法接受一個閉包。此閉包應類型提示它負責呈現的物件類型。通常,stringable 方法應在您的應用程式 AppServiceProvider 類別的 boot 方法中調用

1use Illuminate\Support\Facades\Blade;
2use Money\Money;
3 
4/**
5 * Bootstrap any application services.
6 */
7public function boot(): void
8{
9 Blade::stringable(function (Money $money) {
10 return $money->formatTo('en_GB');
11 });
12}

一旦定義了您的自訂呼應處理程序,您就可以簡單地在您的 Blade 範本中呼應該物件

1Cost: {{ $money }}

自訂 If 語句

當定義簡單的自訂條件語句時,編寫自訂指令有時比必要的更複雜。因此,Blade 提供了 Blade::if 方法,允許您使用閉包快速定義自訂條件指令。例如,讓我們定義一個自訂條件,以檢查應用程式的已配置預設「磁碟」。我們可以在 AppServiceProviderboot 方法中執行此操作

1use Illuminate\Support\Facades\Blade;
2 
3/**
4 * Bootstrap any application services.
5 */
6public function boot(): void
7{
8 Blade::if('disk', function (string $value) {
9 return config('filesystems.default') === $value;
10 });
11}

一旦定義了自訂條件,您就可以在您的範本中使用它

1@disk('local')
2 <!-- The application is using the local disk... -->
3@elsedisk('s3')
4 <!-- The application is using the s3 disk... -->
5@else
6 <!-- The application is using some other disk... -->
7@enddisk
8 
9@unlessdisk('local')
10 <!-- The application is not using the local disk... -->
11@enddisk

Laravel 是最有效率的方式來
建構、部署和監控軟體。