Blade 模板
Blade 範本
- ##簡介
- 模板繼承
- ##Components & Slots
- 顯示資料
- #Blade & JavaScript 框架
- 流程控制
- If 語句
- #Switch 語句
循環變數- 表單
- #引入子視圖
#堆疊服務注入
#自訂If 語句
##############簡介######Blade 是Laravel 提供的一個簡單又強大的模板引擎。和其他流行的 PHP 模板引擎不同,Blade 並不限制你在視圖中使用原生 PHP 程式碼。所有 Blade 視圖檔案都將被編譯成原生的 PHP 程式碼並快取起來,除非它被修改,否則不會重新編譯,這意味著 Blade 基本上不會為你的應用程式增加任何負擔。 Blade 視圖檔案使用 ###.blade.php### 作為檔案副檔名,被存放在 ###resources/views### 目錄。 #########################模板繼承################################################################定義佈局
Blade 的兩個主要優點是模板繼承
和區塊
。為方便入門,讓我們先透過一個簡單的例子來上手。首先,我們來研究一個「主」頁面佈局。因為大多數 web 應用程式會在不同的頁面中使用相同的佈局方式,因此可以很方便地定義單一 Blade 佈局視圖:
<!-- 保存在 resources/views/layouts/app.blade.php 文件中 --> <html> <head> <title>App Name - @yield('title')</title> </head> <body> @section('sidebar') This is the master sidebar. @show <div class="container"> @yield('content') </div> </body> </html>
如你所見,該檔案包含了典型的 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>This is appended to the master sidebar.</p> @endsection @section('content') <p>This is my body content.</p> @endsection
在這個範例中,sidebar
片段利用@parent
指令向佈局的sidebar 追加(而非覆蓋)內容。在渲染視圖時,@parent
指令將會被佈局中的內容取代。
{tip} 和上一個範例相反,這裡的
sidebar
片段使用@endsection
取代@show
# 來結束。@endsection
指令只定義了一個片段,@show
則在定義的同時 立即 yield 這個片段。
Blade 視圖可以使用全域全域view
助手自路由中傳回:
Route::get('blade', function () { return view('child'); });
組件& 插槽
組件和插槽提供了與片段和佈局類似的好處;不過組件和插槽的思維模型更易於理解。我們先來看一個可重複使用的「alert」元件,我們想在應用程式中重複使用它:
<!-- /resources/views/alert.blade.php --> <div class="alert alert-danger"> {{ $slot }} </div>{{ $slot }}### 變數將包含我們想要注入到組件的內容。現在,我們使用 Blade 的 ###@component### 指令來建立這個元件:###
@component('alert') <strong>Whoops!</strong> Something went wrong! @endcomponent###有時候為一個元件定義多個插槽是很有用的。修改 alert 元件以允許其註入 “title”。命名插槽可以透過與其匹配的 “回顯” 變數顯示:###
<!-- /resources/views/alert.blade.php --> <div class="alert alert-danger"> <div class="alert-title">{{ $title }}</div> {{ $slot }} </div>###現在,我們能夠使用 ###@slot### 指令向命名插槽注入內容。不在 ###@slot### 指令內的內容都會傳遞給元件中的 ###$slot### 變數:###
@component('alert') @slot('title') Forbidden @endslot You are not allowed to access this resource!@endcomponent######
向元件傳遞額外的資料
有時你可能需要向元件傳遞額外的資料。在這種情況下,可以把包含資料組織成數組,作為 @component
指令的第二個參數。所有的資料將作為變更提供給元件模板:
@component('alert', ['foo' => 'bar']) ... @endcomponent
給元件起別名
如果元件儲存在子目錄中,你可能會想要給它們一個別名以方便訪問。舉例來說,如果一個Blade 元件儲存在 resources/views/components/alert.blade.php
中,。就可以使用component
方法將components.alert
的別名命名為alert
。 . 通常情況下,這個過程將在AppServiceProvider
的 boot
方法中完成:
use Illuminate\Support\Facades\Blade; Blade::component('components.alert', 'alert');
一旦元件有了別名,就可以使用一條指令渲染它:
@alert(['type' => 'danger']) You are not allowed to access this resource!@endalert
如果沒有額外的插槽,也可以省略元件參數:
@alert You are not allowed to access this resource!@endalert
顯示資料
可以透過包裹在雙花括號內的變數顯示傳遞給Blade 視圖的資料。例如給以下路由:
Route::get('greeting', function () { return view('welcome', ['name' => 'Samantha']); });
就可以這樣利用name
變數顯示其內容:
Hello, {{ $name }}.
{tip} Blade
{ }}
語句是自動經過 PHP 的htmlspecialchars
函數傳遞來防範 XSS 攻擊的。
不限於顯示傳遞給視圖的變數的內容,你也可以顯示任一 PHP 函數的結果。實際上,你可以在Blade 的回顯語句中放置你想要的任意PHP 代碼:
The current UNIX timestamp is {{ time() }}.
顯示非轉義字元
預設情況下, Blade中{{ }}
語句自動經由PHP 的htmlspecialchars
函數傳遞以防範XSS 攻擊。如果不希望資料被轉義,可以使用下面的語法:
Hello, {!! $name !!}.
{note} 在回顯應用程式的使用者提供的內容時需要謹慎小心。在顯示使用者提供的資料時,有必要一直使用雙花括號語法轉義來防範 XSS 攻擊。
渲染JSON
有時,為了初始化一個JavaScript 變量,你可能會向視圖傳遞一個數據,並將其渲染成JSON:
<script> var app = <?php echo json_encode($array); ?>; </script>
不過,你可以使用@json
Blade 指令來取代手動呼叫json_encode
函數:
<script> var app = @json($array); </script>
HTML 實體編碼
預設情況下,Blade (以及Laravel 的e
助手)將對HTML 實體雙重編碼。如果要停用雙重編碼,可以在AppServiceProvider
的boot
中呼叫Blade::withoutDoubleEncoding
方法:
<?php namespace App\Providers; use Illuminate\Support\Facades\Blade; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider{ /** * 引导任意应用服务。 * * @return void */ public function boot() { Blade::withoutDoubleEncoding(); } }#
Blade & JavaScript 框架
由於許多JavaScript 框架也使用花括號表明給定的表達式將要在瀏覽器中顯示, 可以使用@
符號通知Blade 渲染引擎某個表達式應保持不變。範例如下:
<h1>Laravel</h1>Hello, @{{ name }}.
在這個範例中, @
符號將會被Blade 刪除;在Blade 引擎中{{ name }}
表達式將保持不變,取而代之的是JavaScript 引擎將渲染該表達式。
@verbatim
指令
如果要在大段的範本中JavaScript 變量,則可以將HTML 包裹在@verbatim
指令中,這樣就不需要為每個Blade 回顯語句新增@
符號:
@verbatim <div class="container"> Hello, {{ name }}. </div>@endverbatim
控制結構
除了模板繼承和資料顯示, Blade 還為分支和循環等PHP 控制結構提供了方便的捷徑。這些捷徑提供了乾淨、簡單地處理 PHP 控制結構的方法,同時保持了與 PHP 中的對應結構的相似性。
If 語句
可以使用@if
、 @elseif
、 @else
和@endif
指令建構if
語句。這些指令的功能與對應的PHP 指令相同:
@if (count($records) === 1) I have one record! @elseif (count($records) > 1) I have multiple records! @else I don't have any records! @endif
方便起見, Blade 還提供了@unless
指令:
@unless (Auth::check()) You are not signed in.@endunless
除了已經討論過的條件指令, @isset
和@empty
指令可以作為各自對應的PHP 函數的捷徑:
@isset($records) // $records 被定义且不是 null... @endisset @empty($records) // $records 为空... @endempty
身份驗證指令
@auth
和
指令能夠用於快速確定當前使用者是經過身份驗證的,還是一個訪客:
如果需要,可以在使用@auth // 此用户身份已验证...@endauth
@guest // 此用户身份未验证...@endguest
@auth
和
@auth('admin') // 此用户身份已验证...@endauth @guest('admin') // 此用户身份未验证...@endguest
片段指令可以使用
Switch 指令可以使用
@switch
、 @case
、 @break
、 @default
與
指令建構switch 語句:@switch($i)
@case(1)
First case...
@break
@case(2)
Second case...
@break
@default
Default case...@endswitch
循環
除了分支語句,Blade 也提供了與 PHP 的迴圈結構相同的簡化指令。這些指令的功能也與對應的PHP 指令相同:
@for ($i = 0; $i < 10; $i++) The current value is {{ $i }} @endfor @foreach ($users as $user) <p>This is user {{ $user->id }}</p> @endforeach @forelse ($users as $user) <li>{{ $user->name }}</li> @empty <p>No users</p> @endforelse @while (true) <p>I'm looping forever.</p> @endwhile
{tip} 迴圈中可以使用循環變數 取得迴圈的可評估訊息,例如現在是處於迴圈的第一次迭代還是最後一次迭代中:
在循環中,也可以終結循環或路過本次迭代:
@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
循環變數
循環過程中,在循環體內有一個可用的$ loop
變數。該變數提供了用於存取諸如當前循環的索引、當前是否為第一次或最後一次循環之類的少數有用的信息的途徑:
@foreach ($users as $user) @if ($loop->first) This is the first iteration. @endif @if ($loop->last) This is the last iteration. @endif <p>This is user {{ $user->id }}</p> @endforeach
在嵌套循環中,可以藉助parent
屬性存取父循環的$loop
變數:
@foreach ($users as $user) @foreach ($user->posts as $post) @if ($loop->parent->first) This is first iteration of the parent loop. @endif @endforeach@endforeach
$loop
變數也包含其它幾種有用的屬性:
#屬性 | 描述 |
---|---|
#$loop->index | #當前迭代的索引(從0 開始計數)。 |
$loop->iteration | #目前循環迭代 (從 1 開始計算)。 |
$loop->remaining | 迴圈中剩餘迭代的數量。 |
$loop->count | #被迭代的陣列元素的總數。 |
$loop->first | 是否為迴圈的第一次迭代。 |
$loop->last | #是否為循環的最後一次迭代。 |
$loop->depth | #目前迭代的巢狀深度層級數。 |
$loop->parent | #巢狀迴圈中,父迴圈的迴圈變數 |
註解
Blade 也允許在視圖中定義註解。不過與HTML 註解不同,Blade 註解不會包含在傳回給應用程式的HTML 中:
{{-- This comment will not be present in the rendered HTML --}}##PHP #某些情況下,在視圖中嵌入PHP 程式碼很有用。可以在模板中使用
@php 指令執行原生的PHP 程式碼區塊:
@php //@endphp
{tip} 儘管Blade 提供了這個特性,但頻繁使用意味著模板中嵌入了過多的邏輯。表單CSRF 域只要在應用程式中定義了HTML 表單,就一定要在表單中包含隱藏的CSRF 令牌域,這樣一來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># 介紹子視圖Blade 的
@include 指令可讓你從其它視圖引入Blade 視圖。父視圖中所有可用的變數都將在被引入的視圖中可用:
<div> @include('shared.errors') <form> <!-- Form Contents --> </form> </div>被包含的視圖不僅會繼承父視圖的所有可用數據,還能夠以數組形式向被包含的視圖傳遞額外資料:
@include('view.name', ['some' => 'data'])如果傳遞給
@include 不存在的視圖,Laravel 會拋出錯誤。想要包含一個無法確定存在與否的視圖,需要使用
@includeIf 指令:
@includeIf('view.name', ['some' => 'data'])想要包含一個依賴給定布林條件的視圖,可以使用
@ includeWhen 指令:
@includeWhen($boolean, 'view.name', ['some' => 'data'])要包含給定視圖陣列中第一個存在的視圖,可以使用
includeFirst 指令:
@includeFirst(['custom.admin', 'admin'], ['some' => 'data'])
{note } 應盡量避免在Blade 視圖中使用__DIR__
和
__FILE__魔術常數,因為它們將指向快取中經過編譯的視圖的位置。
給被包含的視圖起別名
如果你的 Blade 被包含視圖們儲存在子目錄中,你可能會想要為它們起個易於存取的別名。例如,一個帶有以下內容的Blade 視圖內容被儲存在resources/views/includes/input.blade.php
檔案中:
<input type="{{ $type ?? 'text' }}">
可以使用include
方法為 includes.input
取一個叫做input
的別名。通常,這會在AppServiceProvider
的boot
方法中完成:
use Illuminate\Support\Facades\Blade; Blade::include('includes.input', 'input');
一旦被包含的視圖擁有了別名,就可以像Blade 指令一樣使用別名渲染它:
@input(['type' => 'email'])
為集合渲染視圖
可以使用Blade 的@each
指令在一行中整合循環和包含:
@each('view.name', $jobs, 'job')
第一個參數是渲染數組或集合的每個元素的視圖片段。第二個參數是希望被迭代的陣列或集合,第三個參數則是將被指派給視圖中目前迭代的變數名稱。例如,想要迭代 jobs
數組,通常會在視圖片段中使用 job
變數來存取每個任務。目前迭代的 key 將作為視圖片段中的 key
變數。
也可以向 @each
指令傳遞第四個參數。這個參數是當給定數組為空時要渲染的視圖片段。
@each('view.name', $jobs, 'job', 'view.empty')
{note} 使用
@each
渲染視圖,無法從父視圖繼承變數。如果子視圖需要這些變量,就必須使用@foreach
和@include
來取代它。
堆疊
Blade 允許你將視圖壓入堆疊,這些視圖能夠在其它視圖或佈局中被渲染。這在子視圖中指定需要的 JavaScript 函式庫時非常有用:
@push('scripts') <script src="/example.js"> </script> @endpush
如果需要,可以多次壓入堆疊。透過向 @stack
指令傳遞堆疊名稱來完成堆疊內容的渲染:
<head> <!-- 头部内容 --> @stack('scripts') </head>
如果想要將內容預置在堆疊頂,則需要使用@prepend
# 指令:
@push('scripts') This will be second...@endpush// 然后... @prepend('scripts') This will be first... @endprepend
Service 注入
@inject
#Service 注入
@inject 指令可以用於自Laravel 的服務容器中取得服務。傳遞給
@inject@inject('metrics', 'App\Services\MetricsService') <div> Monthly Revenue: {{ $metrics->monthlyRevenue() }}.</div>######## ##########
擴充 Blade
Blade 允許你使用 directive
方法自訂指令。當 Blade 編譯器遇到自訂指令時,這會呼叫該指令包含的表達式提供的回呼。
下面的範例建立了@datetime($var)
指令,一個格式化給定的DateTime
的實例$var
:
<?php namespace App\Providers; use Illuminate\Support\Facades\Blade; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider{ /** * 执行注册后引导服务. * * @return void */ public function boot() { Blade::directive('datetime', function ($expression) { return "<?php echo ($expression)->format('m/d/Y H:i'); ?>"; }); } /** * 在容器中注册绑定. * * @return void */ public function register() { // } }
如你所見,我們將在傳遞給該指令的任意表達式中鍊式呼叫 format
方法。在這個範例中,指令將產生以下原生 PHP 程式碼:
<?php echo ($var)->format('m/d/Y H:i'); ?>
{note} 在更新 Blade 指令的邏輯之後,需要 Blade 視圖的所有快取。可以使用
view:clear
Artisan 指令刪除 Blade 視圖快取。
自訂If 語句
在定義簡單的、自訂條件語句時,寫自定義指令比必須的步驟複雜。在這種情況下,Blade 提供了 Blade::if
方法,它允許你使用閉包快速度定義條件指令。例如,定義一個校驗目前應用環境的自訂指令,可以在 AppServiceProvider
的boot
方法中這樣做:
use Illuminate\Support\Facades\Blade; /** * 执行注册后引导服务 * * @return void */ public function boot(){ Blade::if('env', function ($environment) { return app()->environment($environment); }); }
一旦定義了自訂條件指令,就可以在模板中輕鬆的使用:
@env('local') // 应用在本地环境中运行... @elseenv('testing') // 应用在测试环境中运行... @else // 应用没有在本地和测试环境中运行... @endenv