Blade là một công cụ tạo template đơn giản nhưng mạnh mẽ được đi kèm cùng với Laravel. Không giống như các công cụ tạo template phổ biến khác của PHP, Blade không hạn chế bạn sử dụng code PHP trong view của bạn. Trên thực tế, tất cả các view Blade được biên dịch thành code PHP và được lưu vào trong cache, cho đến khi chúng được sửa đổi, có nghĩa là về cơ bản Blade không làm tăng chi phí chung cho application của bạn. Các file Blade sử dụng phần đuôi mở rộng là .blade.php
và thường được lưu trữ trong thư mục resources/views
.
Hai trong số những lợi ích chính của việc sử dụng Blade là kế thừa template và sections. Để bắt đầu, chúng ta hãy xem một ví dụ đơn giản. Đầu tiên, chúng ta hãy xem thử một layout trang "master". Vì hầu hết tất cả các trang web đều cố gắng duy trì một layout chung cho tất cả các trang khác nhau, nên Blade rất tiện cho việc định nghĩa các loại layout này chỉ trong một file view Blade duy nhất:
<!-- Stored in 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>
Như bạn có thể thấy, file này chứa code HTML. Tuy nhiên, hãy lưu ý các lệnh @section
và @yield
. Lệnh @section
, như cái tên của nó, nó dùng để định nghĩa một phần của nội dung, trong khi lệnh @yield
được sử dụng để hiển thị nội dung của một phần nhất định.
Vậy chúng ta đã định nghĩa xong một layout cho application của bạn, bây giờ hãy bắt đầu bằng một định nghĩa của một trang layout con kế thừa từ layout ở trên.
Khi định nghĩa một view con, bạn hãy sử dụng lệnh @extends
của Blade để chỉ định layout nào mà view con đó sẽ được "kế thừa". Các view mà được mở rộng từ một layout Blade có thể đưa thêm nội dung vào các section của layout bằng cách sử dụng các lệnh @section
. Hãy nhớ rằng, như ví dụ ở trên, nội dung của các section này sẽ được hiển thị trong layout bằng cách sử dụng @yield
:
<!-- Stored in 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
Trong ví dụ này, section sidebar
đang sử dụng lệnh @parent
để nối thêm vào (chứ không phải ghi đè) sidebar của layout. Lệnh @parent
sẽ được thay thế bằng nội dung của layout khi view được hiển thị.
{tip} Trái ngược với ví dụ trước đó, section
sidebar
này kết thúc bằng@endsection
thay vì@show
. Lệnh@endsection
sẽ định nghĩa kết thúc một section trong khi@show
cũng sẽ định nghĩa kết thúc một section nhưng nó cũng định nghĩa thêm một lệnh@yield
để cho layout con để có thể định nghĩa thêm nội dung vào layout chính.
Blade view có thể được trả về từ route khi dùng với global helper view
:
Route::get('blade', function () {
return view('child');
});
Các component và slot cung cấp nhiều lợi ích tương tự như các section và layout; tuy nhiên, có một số loại của component và slot là dễ hiểu hơn. Trước tiên, hãy tưởng tượng một component "cảnh báo" có thể tái sử dụng và chúng ta muốn sử dụng lại nó trong suốt quá trình phát triển ứng dụng của bạn:
<!-- /resources/views/alert.blade.php -->
<div class="alert alert-danger">
{{ $slot }}
</div>
Biến {{ $slot }}
sẽ chứa nội dung mà chúng ta muốn đưa vào component. Bây giờ, để sử dụng component này, chúng ta có thể sử dụng lệnh @component
Blade:
@component('alert')
<strong>Whoops!</strong> Something went wrong!
@endcomponent
Thỉnh thoảng chúng ra sẽ cần định nghĩa nhiều slot cho một component. Hãy chỉnh sửa component cảnh báo của chúng ta để cho phép injection một "title". Các slot đã được đặt tên có thể được hiển thị bằng cách "echoing" biến khớp với tên của chúng:
<!-- /resources/views/alert.blade.php -->
<div class="alert alert-danger">
<div class="alert-title">{{ $title }}</div>
{{ $slot }}
</div>
Bây giờ, chúng ta có thể inject nội dung vào slot đã được đặt tên bằng cách sử dụng lệnh @slot
. Bất kỳ nội dung nào mà không nằm trong lệnh @slot
sẽ được truyền đến component trong biến $slot
:
@component('alert')
@slot('title')
Forbidden
@endslot
You are not allowed to access this resource!
@endcomponent
Thỉnh thoảng bạn có thể cần truyền thêm dữ liệu cho một component. Bạn có thể truyền một mảng dữ liệu làm tham số thứ hai cho lệnh @component
. Tất cả các dữ liệu sẽ được truyền cho component template dưới dạng các biến:
@component('alert', ['foo' => 'bar'])
...
@endcomponent
Bạn có thể hiển thị dữ liệu đã được truyền đến Blade view của bạn bằng cách đặt tên biến vào trong hai lần dấu ngoặc nhọn. Ví dụ: một route như sau:
Route::get('greeting', function () {
return view('welcome', ['name' => 'Samantha']);
});
Bạn có thể hiển thị nội dung của biến name
như thế này:
Hello, {{ $name }}.
Tất nhiên, bạn không bị giới hạn trong việc hiển thị nội dung của các biến đã được truyền đến view. Bạn cũng có thể echo ra kết quả với bất kỳ hàm PHP nào tương tự. Thực tế, bạn có thể set bất kỳ code PHP nào mà bạn muốn vào trong lệnh echo của Blade:
The current UNIX timestamp is {{ time() }}.
{tip} Các câu lệnh Blade
{{ }}
này sẽ được tự động gửi qua hàmhtmlspecialchars
của PHP để ngăn chặn các cuộc tấn công XSS.
Mặc định, các câu lệnh Blade {{ }}
này sẽ được tự động gửi qua hàm htmlspecialchars
của PHP để ngăn chặn các cuộc tấn công XSS. Nếu bạn không muốn dữ liệu của bạn được escaped, bạn có thể sử dụng cú pháp sau:
Hello, {!! $name !!}.
{note} Bạn hãy cẩn thận khi hiển thị một nội dung mà được cung cấp bởi người dùng. Hãy luôn sử dụng escaped với cú pháp hai lần dấu ngoặc nhọn để ngăn chặn các cuộc tấn công XSS khi hiển thị dữ liệu do người dùng cung cấp.
Thỉnh thoảng bạn có thể muốn truyền một mảng vào view của bạn với ý định là hiển thị nó dưới dạng một chuỗi JSON để khởi tạo một biến JavaScript. Ví dụ:
<script>
var app = <?php echo json_encode($array); ?>;
</script>
Tuy nhiên, thay vì gọi thủ công json_encode
, bạn có thể sử dụng lệnh Blade @json
:
<script>
var app = @json($array);
</script>
Do nhiều framework JavaScript cũng sử dụng hai lần dấu ngoặc nhọn để hiển thị dữ liệu trong trình duyệt, nên bạn có thể sử dụng ký hiệu @
để thông báo cho Blade rendering engine là biểu thức này sẽ không được laravel rendering. Ví dụ:
<h1>Laravel</h1>
Hello, @{{ name }}.
Trong ví dụ này, ký hiệu @
sẽ bị xóa bởi Blade; tuy nhiên, biểu thức {{ name }}
sẽ vẫn còn và sẽ không được xử lý bởi Blade engine, điều này cho phép các biểu thức đó sẽ được render bởi framework JavaScript của bạn.
@verbatim
Nếu trong template của bạn đang hiển thị nhiều biến JavaScript, bạn có thể bao bọc các lệnh đó trong lệnh @verbatim
để bạn không phải đặt tiền tố cho mỗi câu lệnh echo Blade bằng ký hiệu @
:
@verbatim
<div class="container">
Hello, {{ name }}.
</div>
@endverbatim
Ngoài việc kế thừa template và hiển thị dữ liệu, Blade cũng cung cấp các shortcut cho các cấu trúc điều khiển PHP phổ biến, chẳng hạn như các câu lệnh và các vòng lặp có điều kiện. Các shortcut này cung cấp một cách làm việc rất ngắn gọn, gọn gàng với các cấu trúc điều khiển PHP, trong khi vẫn quen thuộc với các hàm tương tự trong PHP.
Bạn có thể xây dựng các câu lệnh if
bằng cách sử dụng các lệnh @if
, @elseif
, @else
, và @endif
. Các lệnh này hoạt động giống hệt với các hàm tương tự trong 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
Để thuận tiện, Blade cũng cung cấp một lệnh @unless
:
@unless (Auth::check())
You are not signed in.
@endunless
Ngoài các lệnh có điều kiện đã được thảo luận ở trên, các lệnh @isset
và @empty
cũng có thể được sử dụng làm các shortcut cho các hàm PHP tương ứng của chúng:
@isset($records)
// $records is defined and is not null...
@endisset
@empty($records)
// $records is "empty"...
@endempty
Các lệnh @auth
và @guest
có thể được sử dụng để xác định xem người dùng hiện tại đã được xác thực chưa? hay là khách:
@auth
// The user is authenticated...
@endauth
@guest
// The user is not authenticated...
@endguest
Nếu cần, bạn có thể chỉ định thêm authentication guard cần được kiểm tra khi sử dụng các lệnh @auth
và @guest
:
@auth('admin')
// The user is authenticated...
@endauth
@guest('admin')
// The user is not authenticated...
@endguest
Bạn có thể kiểm tra xem một section có nội dung hay không bằng cách sử dụng lệnh @hasSection
:
@hasSection('navigation')
<div class="pull-right">
@yield('navigation')
</div>
<div class="clearfix"></div>
@endif
Các câu lệnh switch có thể được xây dựng bằng cách sử dụng các lệnh @switch
, @case
, @break
, @default
và @endswitch
:
@switch($i)
@case(1)
First case...
@break
@case(2)
Second case...
@break
@default
Default case...
@endswitch
Ngoài các câu lệnh có điều kiện, Blade cung cấp các lệnh đơn giản để làm việc với các cấu trúc vòng lặp của PHP. Một lần nữa, các lệnh này hoạt động giống hệt với các hàm PHP tương ứng của chúng:
@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} Khi lặp, bạn có thể sử dụng loop variable để nhận về các thông tin có giá trị về vòng lặp, chẳng hạn như bạn đang ở vòng lặp đầu tiên hoặc vòng lặp cuối cùng.
Khi sử dụng các vòng lặp, bạn cũng có thể kết thúc vòng lặp hoặc bỏ qua vòng lặp hiện tại:
@foreach ($users as $user)
@if ($user->type == 1)
@continue
@endif
<li>{{ $user->name }}</li>
@if ($user->number == 5)
@break
@endif
@endforeach
Bạn cũng có thể thêm các điều kiện và khai báo lệnh đó trong một dòng:
@foreach ($users as $user)
@continue($user->type == 1)
<li>{{ $user->name }}</li>
@break($user->number == 5)
@endforeach
Khi lặp, một biến $loop
sẽ có sẵn bên trong vòng lặp của bạn. Biến này cung cấp quyền truy cập vào một số thông tin hữu ích như vòng lặp hiện tại và liệu đây có phải là vòng lặp đầu tiên hay là vòng lặp cuối cùng:
@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
Nếu bạn đang ở trong một vòng lặp lồng nhau, bạn có thể truy cập vào biến $loop
của vòng lặp cha thông qua thuộc tính parent
:
@foreach ($users as $user)
@foreach ($user->posts as $post)
@if ($loop->parent->first)
This is first iteration of the parent loop.
@endif
@endforeach
@endforeach
Biến $loop
cũng chứa nhiều thuộc tính hữu ích khác:
Property | Description |
---|---|
$loop->index |
The index of the current loop iteration (starts at 0). |
$loop->iteration |
The current loop iteration (starts at 1). |
$loop->remaining |
The iteration 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->depth |
The nesting level of the current loop. |
$loop->parent |
When in a nested loop, the parent's loop variable. |
Blade cũng cho phép bạn định nghĩa các comment trong view của bạn. Tuy nhiên, không giống như comment trong HTML, comment trong Blade sẽ không được hiển thị vào trong HTML do application của bạn trả về:
{{-- This comment will not be present in the rendered HTML --}}
Trong một số trường hợp, có thể bạn cần nhúng code PHP vào trong view của bạn. Bạn có thể sử dụng lệnh Blade @php
để thực thi một khối lệnh PHP đơn giản trong template của bạn:
@php
//
@endphp
{tip} Mặc dù Blade cung cấp tính năng này, nhưng việc sử dụng nó thường xuyên có thể là một tín hiệu cho thấy bạn đang có quá nhiều logic đang được nhúng vào trong template của bạn.
Lệnh @include
của Blade cho phép bạn thêm một view Blade khác vào trong view hiện tại. Tất cả các biến đã có trong view hiện tại cũng sẽ có trong view được thêm:
<div>
@include('shared.errors')
<form>
<!-- Form Contents -->
</form>
</div>
Mặc dù view được thêm sẽ kế thừa tất cả các dữ liệu có sẵn trong view chính, nhưng bạn cũng có thể chuyển thêm một mảng dữ liệu bổ sung cho view được thêm:
@include('view.name', ['some' => 'data'])
Tất nhiên, nếu bạn thử @include
một view không tồn tại, thì Laravel sẽ đưa ra một lỗi. Nếu bạn muốn thêm một view có thể có hoặc có thể không tồn tại, thì bạn nên sử dụng lệnh @includeIf
:
@includeIf('view.name', ['some' => 'data'])
Nếu bạn muốn @include
một view tùy thuộc vào một điều kiện boolean nhất định, bạn có thể sử dụng lệnh @includeWhen
:
@includeWhen($boolean, 'view.name', ['some' => 'data'])
Để thêm view đầu tiên tồn tại từ một list view nhất định, bạn có thể sử dụng lệnh includeFirst
:
@includeFirst(['custom.admin', 'admin'], ['some' => 'data'])
{note} Bạn nên tránh sử dụng các hằng số
__DIR__
và__FILE__
trong view Blade của bạn, vì chúng sẽ dẫn đến vị trí view sẽ được cache và compile.
Bạn có thể kết hợp các vòng lặp và các include vào một dòng lệnh @each
của Blade:
@each('view.name', $jobs, 'job')
Tham số đầu tiên là tên view con để hiển thị cho từng phần tử trong mảng hoặc collection. Tham số thứ hai là mảng hoặc collection mà bạn muốn lặp, trong khi tham số thứ ba là tên biến sẽ được gán cho mỗi lần lặp trong view. Vậy, ví dụ, nếu như bạn đang lặp một mảng jobs
, thông thường bạn sẽ muốn truy cập từng job dưới dạng tên một biến job
trong view con. Key cho vòng lặp hiện tại sẽ có sẵn dưới dạng biến key
trong view con của bạn.
Bạn cũng có thể truyền một tham số thứ tư cho lệnh @each
. Tham số này định nghĩa view nào sẽ được hiển thị nếu mảng đó trống.
@each('view.name', $jobs, 'job', 'view.empty')
{note} View được hiển thị qua
@each
sẽ không kế thừa các biến từ view cha. Nếu bạn muốn các view con của bạn có các biến này, bạn có thể sử dụng@foreach
và@include
thay thế.
Blade cho phép bạn khai báo thêm các file hoặc các biến vào trong các stack đã được tên, để có thể được hiển thị ở một nơi khác trong view hoặc layout. Điều này có thể đặc biệt hữu ích để định nghĩa một thư viện JavaScript nào đó theo yêu cầu của view con của bạn:
@push('scripts')
<script src="/example.js"></script>
@endpush
Bạn có thể khai báo cho một stack nhiều lần nếu cần. Để hiển thị nội dung stack hoàn chỉnh, truyền tên của stack vào lệnh @stack
:
<head>
<!-- Head Contents -->
@stack('scripts')
</head>
Lệnh @inject
có thể được sử dụng để lấy một service ra từ service container. Tham số đầu tiên được truyền vào @inject
là tên biến mà service sẽ được set, trong khi tham số thứ hai là tên class hoặc là tên một interface của service mà bạn muốn resolve:
@inject('metrics', 'App\Services\MetricsService')
<div>
Monthly Revenue: {{ $metrics->monthlyRevenue() }}.
</div>
Blade cho phép bạn định nghĩa thêm các lệnh tùy biến của riêng bạn bằng phương thức directive
. Khi trình biên dịch Blade gặp phải các lệnh tùy biến này, nó sẽ tự động gọi đến hàm callback đã được khai báo cho lệnh này.
Ví dụ sau đây sẽ tạo ra một lệnh @datetime($var)
để format lại một biến $var
đã cho, và biến này phải là một instance của DateTime
:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
Blade::directive('datetime', function ($expression) {
return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
});
}
/**
* Register bindings in the container.
*
* @return void
*/
public function register()
{
//
}
}
Như bạn có thể thấy, chúng ta sẽ nối phương thức format
vào bất kỳ biểu thức nào được truyền vào lệnh. Vì vậy, trong ví dụ này, code PHP cuối cùng được tạo ra bởi lệnh này sẽ như sau:
<?php echo ($var)->format('m/d/Y H:i'); ?>
{note} Sau khi cập nhật logic của lệnh Blade, bạn sẽ cần xóa tất cả các view Blade đã được lưu trong bộ nhớ cache. Các view Blade được lưu trong bộ nhớ cache có thể được loại bỏ bằng lệnh Artisan
view:clear
.
Lập trình một lệnh tùy biến đôi khi lại là phức tạp hơn là định nghĩa một câu lệnh điều kiện tùy biến đơn giản. Vì lý do đó, Blade cung cấp phương thức Blade::if
cho phép bạn nhanh chóng định nghĩa các lệnh tùy biến có điều kiện bằng cách sử dụng Closures. Ví dụ: hãy định nghĩa một điều kiện tùy biến có thể kiểm tra biến môi trường hiện tại của application. Chúng ta có thể làm điều này trong phương thức boot
của AppServiceProvider
:
use Illuminate\Support\Facades\Blade;
/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
Blade::if('env', function ($environment) {
return app()->environment($environment);
});
}
Khi điều kiện tùy biến đã được định nghĩa xong, chúng ta có thể dễ dàng sử dụng nó trên các template của bạn:
@env('local')
// The application is in the local environment...
@elseenv('testing')
// The application is in the testing environment...
@else
// The application is not in the local or testing environment...
@endenv
entry