简介
Blade 是一个由 Laravel 提供的简单、当功能强大的模板引擎。同其他流行的 PHP 模板引擎不同,Blade 不限制你在视图中使用原生的 PHP 代码。事实上,所有的 Blade 模板都会编译为原生 PHP 代码并缓存起来,直到下次它们更改,意味着 Blade 基本不会增加的应用的消耗。Blade 视图文件使用 .blade.php
文件后缀,一般存放在 resources/views
目录。
模板继承
定义布局
使用 Blade 两个主要的好处是模板继承和部件。作为开始,我们来看一个简单的例子。首先,我们来看一个“主”页面布局。由于 WEB 应用一般在多个不同的页面使用统一的布局,把这个布局定义为一个单独的 Blade 将会是非常方便的:
<!-- 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>
你可以看到,这个文件包含了典型的 HTML 语法。然而,请注意 @section
和 @yield
指令。@section
指令,正如名字一样,定义一个内容的部件,而 @yield
指令则用来为给定的部件展示内容。
既然我们已经为应用定义了布局,现在让我们来定义一个继承这个布局的子页面。
扩展布局
当定义子视图时,使用 @extends
指令指定子视图需要“继承”哪个布局。扩展自 Blade 布局的视图可以使用 @section
指令向布局的部件注入内容。记住,正如上面例子所见,这些内容使用 @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
在这个例子中,sidebar
部件使用 @parent
指令追加(而非覆盖)内容到布局的工具栏。当视图渲染时,@parent
会被布局中的内容取代。
Blade 视图可以通过全局的 view
辅助函数返回给路由:
Route::get('blade', function () { return view('child'); });
展示数据
你可以通过使用双花括号包裹传递给 Blade 视图的数据来展示它们。例如,给定下面的路由:
Route::get('greeting', function () { return view('welcome', ['name' => 'Samantha']); });
你可以这样展示 name
变量的内容:
Hello, {{ $name }}.
当然,没有显示你展示传递给视图的变量的内容。你还可以输入 PHP 函数的结果。事实上,你可以添加任何 PHP 代码来替代 Blade 的输出语句:
The current UNIX timestamp is {{ time() }}
{{ }}
语法会自动传递给 PHP 的 htmlentities
函数以避免 XSS 攻击。数据存在时才输出
有时候你可能想输出一个变量,但是你不确定变量是否被设置了。我们可以通过一个冗长的 PHP 代码来表达:
{{ isset($name) ? $name : 'Default' }}
然而,除了使用三元表达式,Blade 还为你提供了下面这个捷径,它会编译为上面的三元表达式:
{{ $name or 'Default' }}
在这个例子中,如果 $name
存在,它的值将会被展示,然而,如果不存在,则会展示 Default
字符。
展示未转义的数据
默认情况下,Blade 的 {{ }}
语法会自动传递给 PHP 的 htmlentities
函数来避免 XSS 攻击。如果你不希望数据被转义,你可以使用下面的语法:
Hello, {!! $name !!}.
Blade & JavaScript 框架
由于很多 JavaScript 框架也使用双花括号来表示应当展示在视图中的表达式,你应当使用 @
符号来告诉 Blade 渲染引擎这个表达式保留原样。例如:
<h1>Laravel</h1> Hello, @{{ name }}.
在这个例子中,@
符号将会被 Blade 移除;然而 {{ name }}
表达式会被 Blade 引擎保持原样,允许它留着被 JavaScript 框架渲染。
@verbatim
指令
如果你在模板的很大一部分展示 JavaScript 变量,你可以使用 @verbatim
包裹这段 HTML 代码,这样就不需要在每个 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
循环
除了条件表达式,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
在使用循环时,你也可以结束循环或跳出当前循环:
@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 | 在嵌套循环中,父循环的 $loop 变量 |
注释
Blade 还允许你在视图中定义注释。然而,同 HTML 注释不同,Blade 不包含在应用返回的 HTML 中:
{{-- This comment will not be present in the rendered HTML --}}
包含子视图
Blade 的 @include
指令允许你在一个视图中包含另一个子视图。所有在父视图中可用的变量在子视图中同样可用:
<div> @include('shared.errors') <form> <!-- Form Contents --> </form> </div>
虽然被包含的视图会继承父视图的所有变量,你还可以向被包含的视图传递一个额外的数据数组:
@include('view.name', ['some' => 'data'])
__DIR__
和 __FILE__
常量,因为它们会指向缓存、编译过的视图。为集合渲染视图
你可以使用 Blade 的 @each
变量结合循环包含在一行:
@each('view.name', $jobs, 'job')
第一个参数是每一个数组或集合元素要渲染的视图部分,第二个参数是你希望迭代的数组或集合,而第三个参数是当前迭代传递给视图的变量名。所以,例如,如果你迭代一个 jobs
数组,一般来说在视图部分你希望使用 job
变量来访问每一个任务。当前迭代的键将以 key
变量传递给视图。
你还可以给 @each
指令传递第四个参数。这个参数表示给定数组为空时将会渲染的视图:
@each('view.name', $jobs, 'job', 'view.empty')
栈
Blade 允许你把将要在其他视图或布局中渲染的内容推送到命名栈中。这对于在子视图中使用指定的 JavaScript 库非常有用:
@push('scripts') <script src="/example.js"></script> @endpush
你可以根据需要推送尽可能多的内容到栈。要渲染完整的栈的内容,传递栈的名字到 @stack
指令:
<head> <!-- Head Contents --> @stack('scripts') </head>
服务注入
@inject
指令可以用来从服务容器中获取服务。传递给 @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 { /** * 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() { // } }
你可以看到,我们对传递给指令的任何表达式链式调用 format
方法。所以,在这个例子中,指令最终生成的 PHP 为:
<?php echo $var->format('m/d/Y H:i'); ?>
view:clear
指令来删除缓存的 Blade 视图。该篇属于专题:《Laravel 5.3 中文文档》