Skip to content

Blade 模板

介绍

Blade 是 Laravel 提供的简单而强大的模板引擎。与其他流行的 PHP 模板引擎不同,Blade 不限制您在视图中使用纯 PHP 代码。实际上,所有 Blade 视图都被编译成纯 PHP 代码并缓存,直到它们被修改,这意味着 Blade 对您的应用程序几乎没有额外的开销。Blade 视图文件使用 .blade.php 文件扩展名,通常存储在 resources/views 目录中。

模板继承

定义布局

使用 Blade 的两个主要好处是 模板继承部分。首先,让我们看一个简单的例子。首先,我们将检查一个“主”页面布局。由于大多数 Web 应用程序在各个页面上保持相同的总体布局,因此将此布局定义为单个 Blade 视图是很方便的:

php
<!-- 存储在 resources/views/layouts/app.blade.php -->

<html>
    <head>
        <title>应用名称 - @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 在布局中显示:

php
<!-- 存储在 resources/views/child.blade.php -->

@extends('layouts.app')

@section('title', '页面标题')

@section('sidebar')
    @@parent

    <p>这是附加到主侧边栏的内容。</p>
@endsection

@section('content')
    <p>这是我的正文内容。</p>
@endsection

在此示例中,sidebar 部分使用 @@parent 指令将内容附加(而不是覆盖)到布局的侧边栏。视图渲染时,@@parent 指令将被布局的内容替换。

可以使用全局 view 助手从路由返回 Blade 视图:

php
Route::get('blade', function () {
    return view('child');
});

显示数据

您可以通过将变量包裹在大括号中来显示传递给 Blade 视图的数据。例如,给定以下路由:

php
Route::get('greeting', function () {
    return view('welcome', ['name' => 'Samantha']);
});

您可以像这样显示 name 变量的内容:

php
Hello, {{ $name }}.

当然,您不仅限于显示传递给视图的变量的内容。您还可以回显任何 PHP 函数的结果。实际上,您可以在 Blade 回显语句中放置任何您希望的 PHP 代码:

php
当前的 UNIX 时间戳是 {{ time() }}.
exclamation

Blade {{ }} 语句会自动通过 PHP 的 htmlentities 函数以防止 XSS 攻击。

如果存在则回显数据

有时您可能希望回显一个变量,但不确定该变量是否已设置。我们可以用详细的 PHP 代码来表达这一点:

php
{{ isset($name) ? $name : '默认' }}

然而,Blade 为您提供了以下方便的快捷方式,它将被编译为上面的三元语句:

php
{{ $name or '默认' }}

在此示例中,如果 $name 变量存在,则会显示其值。但是,如果不存在,则会显示“默认”一词。

显示未转义的数据

默认情况下,Blade {{ }} 语句会自动通过 PHP 的 htmlentities 函数以防止 XSS 攻击。如果您不希望数据被转义,可以使用以下语法:

php
Hello, {!! $name !!}.
exclamation

在回显用户提供的内容时要非常小心。始终使用转义的双大括号语法以防止在显示用户提供的数据时发生 XSS 攻击。

Blade 与 JavaScript 框架

由于许多 JavaScript 框架也使用“大括号”来表示给定表达式应在浏览器中显示,您可以使用 @ 符号通知 Blade 渲染引擎表达式应保持不变。例如:

php
<h1>Laravel</h1>

Hello, @{{ name }}.

在此示例中,Blade 将删除 @ 符号;然而,{{ name }} 表达式将保持不变,由您的 JavaScript 框架渲染。

@verbatim 指令

如果您在模板的大部分中显示 JavaScript 变量,可以将 HTML 包裹在 @verbatim 指令中,这样就不必在每个 Blade 回显语句前加上 @ 符号:

php
@verbatim
    <div class="container">
        Hello, {{ name }}.
    </div>
@endverbatim

控制结构

除了模板继承和显示数据,Blade 还为常见的 PHP 控制结构提供了方便的快捷方式,例如条件语句和循环。这些快捷方式提供了一种非常简洁的方式来处理 PHP 控制结构,同时也保持了与 PHP 的相似性。

If 语句

您可以使用 @if@elseif@else@endif 指令构建 if 语句。这些指令的功能与其 PHP 对应物完全相同:

php
@if (count($records) === 1)
    我有一条记录!
@elseif (count($records) > 1)
    我有多条记录!
@else
    我没有任何记录!
@endif

为了方便起见,Blade 还提供了一个 @unless 指令:

php
@unless (Auth::check())
    您尚未登录。
@endunless

循环

除了条件语句,Blade 还为处理 PHP 的循环结构提供了简单的指令。同样,这些指令的功能与其 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
lightbulb

在循环时,您可以使用 循环变量 来获取有关循环的有价值信息,例如您是否在循环的第一次或最后一次迭代中。

使用循环时,您还可以结束循环或跳过当前迭代:

php
@foreach ($users as $user)
    @if ($user->type == 1)
        @continue
    @endif

    <li>{{ $user->name }}</li>

    @if ($user->number == 5)
        @break
    @endif
@endforeach

您还可以在一行中包含条件与指令声明:

php
@foreach ($users as $user)
    @continue($user->type == 1)

    <li>{{ $user->name }}</li>

    @break($user->number == 5)
@endforeach

循环变量

在循环时,$loop 变量将在循环内部可用。此变量提供了一些有用的信息,例如当前循环索引以及这是否是循环的第一次或最后一次迭代:

php
@foreach ($users as $user)
    @if ($loop->first)
        这是第一次迭代。
    @endif

    @if ($loop->last)
        这是最后一次迭代。
    @endif

    <p>这是用户 {{ $user->id }}</p>
@endforeach

如果您在嵌套循环中,可以通过 parent 属性访问父循环的 $loop 变量:

php
@foreach ($users as $user)
    @foreach ($user->posts as $post)
        @if ($loop->parent->first)
            这是父循环的第一次迭代。
        @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 中:

php
{{-- 此注释不会出现在渲染的 HTML --}}

PHP

在某些情况下,将 PHP 代码嵌入视图中是有用的。您可以使用 Blade 的 @php 指令在模板中执行一段纯 PHP 代码:

php
@php
    //
@endphp
lightbulb

虽然 Blade 提供了此功能,但频繁使用它可能表明您的模板中嵌入了过多的逻辑。

包含子视图

Blade 的 @include 指令允许您从另一个视图中包含一个 Blade 视图。所有可用于父视图的变量都将可用于包含的视图:

php
<div>
    @include('shared.errors')

    <form>
        <!-- 表单内容 -->
    </form>
</div>

即使包含的视图将继承父视图中可用的所有数据,您也可以将额外的数据数组传递给包含的视图:

php
@include('view.name', ['some' => 'data'])

当然,如果您尝试 @include 一个不存在的视图,Laravel 将抛出错误。如果您希望包含一个可能存在也可能不存在的视图,您应该使用 @includeIf 指令:

php
@includeIf('view.name', ['some' => 'data'])
exclamation

您应该避免在 Blade 视图中使用 __DIR____FILE__ 常量,因为它们将引用缓存的、编译的视图的位置。

为集合渲染视图

您可以将循环和包含合并为一行,使用 Blade 的 @each 指令:

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

第一个参数是要为数组或集合中的每个元素渲染的视图部分。第二个参数是您希望迭代的数组或集合,而第三个参数是将在视图部分中分配给当前迭代的变量名。因此,例如,如果您正在迭代 jobs 数组,通常您希望在视图部分中将每个作业作为 job 变量访问。当前迭代的键将在视图部分中作为 key 变量可用。

您还可以将第四个参数传递给 @each 指令。此参数确定如果给定数组为空,将渲染哪个视图。

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

堆栈

Blade 允许您推送到命名堆栈,这些堆栈可以在另一个视图或布局中渲染。这在指定子视图所需的任何 JavaScript 库时特别有用:

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

您可以根据需要多次推送到堆栈。要渲染完整的堆栈内容,请将堆栈的名称传递给 @stack 指令:

php
<head>
    <!-- 头部内容 -->

    @stack('scripts')
</head>

服务注入

@inject 指令可用于从 Laravel 服务容器 中检索服务。传递给 @inject 的第一个参数是服务将放入的变量的名称,而第二个参数是您希望解析的服务的类或接口名称:

php
@inject('metrics', 'App\Services\MetricsService')

<div>
    月收入:{{ $metrics->monthlyRevenue() }}.
</div>

扩展 Blade

Blade 允许您使用 directive 方法定义自己的自定义指令。当 Blade 编译器遇到自定义指令时,它将使用指令包含的表达式调用提供的回调。

以下示例创建了一个 @datetime($var) 指令,该指令格式化给定的 $var,该变量应为 DateTime 的实例:

php
<?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
<?php echo ($var)->format('m/d/Y H:i'); ?>
exclamation

更新 Blade 指令的逻辑后,您需要删除所有缓存的 Blade 视图。可以使用 view:clear Artisan 命令删除缓存的 Blade 视图。