首页 » Laravel 5.3 中文文档 » 正文

「Laravel 5.3 中文文档」视图 & 模板 – Blade 模板

简介

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() }}
Blade 的 {{ }} 语法会自动传递给 PHP 的 htmlentities 函数以避免 XSS 攻击。

数据存在时才输出

有时候你可能想输出一个变量,但是你不确定变量是否被设置了。我们可以通过一个冗长的 PHP 代码来表达:

{{ isset($name) ? $name : 'Default' }}

然而,除了使用三元表达式,Blade 还为你提供了下面这个捷径,它会编译为上面的三元表达式:

{{ $name or 'Default' }}

在这个例子中,如果 $name 存在,它的值将会被展示,然而,如果不存在,则会展示 Default 字符。

展示未转义的数据

默认情况下,Blade 的 {{ }} 语法会自动传递给 PHP 的 htmlentities 函数来避免 XSS 攻击。如果你不希望数据被转义,你可以使用下面的语法:

Hello, {!! $name !!}.
输出内容时尤其要注意你应用的用户提供的数据。当展示用户提供的数据时,一定要使用双花括号进行转义以避免 XSS 攻击。

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'])
在 Blade 视图中应当避免使用 __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'); ?>
在更新 Blade 指令的逻辑后,你需要删除所有缓存的 Blade 视图,可以通过 view:clear 指令来删除缓存的 Blade 视图。

该篇属于专题:《Laravel 5.3 中文文档

发表评论