Laravel 文档阅读:Blade 模板

2018-10-14  本文已影响88人  晨曦入诗

简介


Blade 是 Laravel 提供的模板引擎,它简单强大。不像其他的 PHP 模板引擎,Blade 允许在视图中使用原生 PHP 代码。实际上,所有的 Blade 视图最终都会被编译成原生 PHP 代码,缓存在 storage/framework/views 文件夹中。Laravel 使用的是这些编译后的缓存文件,而不是视图本身,所以,Blade 对于应用程序来说是零开销的。当你修改了视图文件,那么它会重新编译并缓存,以便使用。Blade 视图以 blade.php 为后缀名,一般存放于 resources/views 文件夹中。

模板继承


定义布局文件

Blade 模板引擎的主要两个优点是 “模板继承” 和 “区块”。举一个简单的例子,一个项目里,几乎所有的页面都是一样的布局,这时候就可以把这个布局提炼出来,作为母版页,继承了这个母版页的的页面都有一样的布局效果,成为母版页的子页。母版页还叫布局文件,布局文件就是一个 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>

布局文件里除了基础的 HTNL 标签,还使用了两个指令:@section@yield@section定义区块,@yield 定义区块里的内容。
下面。来定义布局文件的子页。

继承布局文件

子页中,使用 Blade 的 @extends 指令指定 “继承” 的布局文件,使用 @section 指令为在布局文件中使用 @section@yield 指令的地方注入内容:

<!-- Stored in resources/views/child.blade.php -->

@extends('layouts.app')
@section('title','Page Title')

@section('sidebar')
       <p> This is appended to the master sideebar</p>
@endsection

@section('content')
         <p>This ismy body content. </p>
@endsection

可以看到,在布局文件中使用 @yield 指令的地方,在子页中仍然使用 @section 注入内容;在布局文件中使用 @section 指令定义的一个好处是:在子页中使用 @section 注入时,可以使用 @parent 指令附加(而非重写)在布局文件中的内容,而在布局文件中使用 @yield 指令定义的地方是做不到的。@parent 指令会在视图渲染的时替换成布局文件里的内容。
注意,与在文件布局里定义的 sidebar 不同的是,子页里使用 @endsection 结束,而非 @show 。因为 @endsection 仅用来定义区块,而 @show 是用来定义、立马产出区块的。
从路由中直接返回视图文件,要用到全局辅助函数 helper :

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

组件&插槽


组件和插槽提供了类似布局和区块的优点。而组件和插槽的心智模型更符合直觉。设想一下,在我们的项目中有一个可重复的 “弹框” 组件:

<!-- Stored resource/views/alter.blade.php -->
<div class="alter alter-danger">
       {{ $slot }}
</div>

{{ $slot }} 表示插入组建的内容。构建此组件,是使用 Blade 的@component指令:

@component('alter')
        <strong>Whoops!</strong> Something went wrong!
@endcomponent

在这个场景里,{{ $slot }} 变量的内容是:

<strong>Whoops! </strong> Something went wrong!

有时一个组件需要多个插槽。这时,只需要稍改组件代码,定义一个 “标题” 插槽,这个插槽称命名插槽。命名插槽是通过简单的 “打印” 匹配其名称的变量来显示内容的:

<!-- Stored resources/views/alter.blade.php-->

<div class="alter alter-danger">
         <div class="alter-title">{{ $title }}</div>
            {{ $slot }}
</div>

为名名插槽注入内容,使用 @slot 指令。所有不在 @slot 指令里的内容都会传递给组件里的 $slot 变量。

@compontent ('alter')
         @slot('title')
            Forbidden
         @endslot
     You are not allowed to access this resource!
@edcompontent~ 

为组建传递额外数据:

有时需要为组建件递额外数据。为此,可以为 @conponent 指令传递第二个数组参数。指定要传递的额外。据所有过去的额外数据作为变量,在组件模板里都可以取的:

@component
     <compontent('alter', ['foo' => 'bar');
         .....
@endCompontent 

显示数据

向 Blade 视图传递数据,是通过将变量包裹在 [ ] 里实现的:

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

下面就可以使用 name 变量显示内容了:

Hello! {{ $name }}

{{ }} 是 Blade 视图的打印语句,当然,打印语句里不限制只能打印变量内容,也可以使用 PHP 函数。实际上,打印语句这里可以使用任何 PHP 代码:

The current UNIX timestamp is {{ time() }}

显示非转移数据

默认,所有传递给 Blade {{ }} 语句的内容都会使用 htmlspecialchar 函数处理、将内容转义,避免 XSS 攻击。如果无需转义输出的内容,可以使用下面语法:

Hello! {{!! $name !!}}.

不过千万要小心,应该优先选择使用转义的 {{ }} 语法避免 XXS 攻击。因为,有时你很难避免用户有意的、无意的数据输入。

Blade & JavaScript 框架

由于一些 JavaScript 框架也使用花括号 {{ }} 语法解析内容,为了区分开 Blade 和这些用到的 JavaScript 框架,你可以使用 @ 符号来告诉 Blade 模板引擎说,这个地方不要动,保持原样就可以了:

<h1>Laravel</h1>

Hello! @{{ $name }}

上面例子里, @ 符号会从 Blade 中删除,而 {{ $name }} 会保持原样,用来给你的 JavaScript 框架渲染使用。

@verbatim 指令

如果使用 JavaScript 框架渲染的模块区域很大,这时就可以使用 @verbatim 指令包裹这些模板区域,这样就避免了在每个Blade 打印语句前都跟上 @ 符号的麻烦:

@verbatim
      <div class="container">
         Hello! {{ $name }}
      </div>
@endverbatim

控制结构

除了模板继承和显示数据,Blade 还未常见的 PHP 结构提供了快捷方式,比如条件谈判和循环。这些快捷方式提供了一种非常干净、简洁的控制结构,并且保持了原生 PHP 的形式。

if 语句

构造 if 语句使用 @if@elseif 、@else 和 endif 指令。这些指令和原生 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.
@endless

除了讨论过的条件判断指令,Blade 还提供了 @isset@empty 指令,都与在原生 PHP 里的对应功能相同:

@isset($recodes)
       // $recodes is defined and is not null ...
@endisset

@empty($recodes)
      // $recodes is "empty" ... 
@endempty

认证

@auth@guest 指令用来判断当前用户是认证用户还是游客:

@auth
        // The user is authenticated...
@endauth

@guest
      //  The useris not authenticated...
@endguest

Switch 语句

switch 语句使用 @switch@case@break@default@endswitch 指令构建:

@switch($i)
          @case(1)
                First case...
          @break;
         
          @case(2)
                Second case...
          @break;

          @default
                Default case...
@endswitch

循环

Blade 还提供了循环方面的指令。再一次声明:这里的每一个指令都与原生 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 user </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>
 
   @break($user->number == 5)
@endforeach 

$loop 变量

在循环时,内部有一个可用变量 $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

如果是在嵌套的循环里,就可以使用 $loop 变量的 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 变量提供的有用属性列举如下:

image.png

注释

Blade 的注释语法是 {{-- --}} 。不像 HTML 注释,Blade 模板注释不会出现在最终渲染的 HTML 代码里:

{{-- This is comment will not be present in the rendered HTML --}}

PHP

Blade 允许在一个视图里通过 @include 指令引入一个视图。使用 @include 指令的视图称为父级视图,引入的视图称为子视图。父级视图的所有变量在子视图里都是可以获得的:

<div>
   @include('shared.error')
    <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'])

注意:不要使用 __DIR____FILE__ 常量引入 Blade 视图,因为程序实际使用的是编译后的、缓存在 storage/framework/views 文件夹中的文件。

为集合渲染视图

@each 指令整合了循环数据和引入视图的功能:

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

第一个参数是为数组或者集合中每个元素渲染数据时指定的视图,第二个参数是要便利的数组或集合,第三个参数是当前迭代的元素数据在子视图中的变量名。在上面的例子里,我们遍历的数组是 jobs , 在 view.name 视图里渲染 job 变量,当前迭代的 key 使用 key 变量获取。
也可以为 @each 指令传递第四个参数,这是在给定数组元素为空时渲染的视图:

@each($bollean, 'view.name', [ 'some' => 'data'], 'view.empty')

注意:使用 @each 渲染的视图不从父级模板里继承变量。如果子视图还需要这些变量,你应该使用 foreach@include 指令组合。

堆栈


Blade 允许你使用 @push 指令向命名堆栈里推入内容,命令堆栈以 @stack 指令定义,可以定义在普通视图或者布局文件里,推入的内容会在视图或者布局文件里渲染出来。这在为子视图添加额外的 JavaScript 库的场景下特别有用。

<!-- 在视图或者布局文件里定义堆栈 -->
<head>
    <!-- Head Contents -->
    @stack('scripts')
</head>

<!-- 在子视图中推入堆栈内容 -->
@push('scripts')
    <script src="/example.js"></script>
@endpush

你可以尽你自己所需的多次向堆栈推入数据。

服务注入


@inject 指令可以从 Laravel 的服务提供者中获得服务。传递给 @inject 指令的第一个参数是一个变量名,获得的服务就是存放在这个变量里,第二个参数就是你要解析的服务的类名或接口名。

@inject('metrics', 'App\Services\MetricesService')

<div>
    Monthly Revenue: {{ $metrics->monthlyRevenue() }}.
</div>

扩展 Blade


Blade 允许你使用 directive 方法创建自定义指令。当 Blade 方法遇到自定义指令时,会将接收到的表达式 (expression)放在自定义指令的回调闭包里处理。
在下面的例子里,我们创建了一个 @datatime($var) 指令,$var应该是一个DateTime 实例:

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 方法。在这个例子里,@datetime($var) 指令最终生成的 PHP 代码如下:

<?php echo ($var)->format('m/d/Y H:i'); ?>

注意:在更新自定义指令后,需要删除所有的视图文件,可以用 view:cache Artisan 命令实现。

自定义 if 语句

当自定义涉及简单的条件判断时,使用 Blade::directive 的方式可能会变得稍复杂些。为此, Blade 引入了 Blade::if 方法使用闭包来快速自定义条件判断指令。例如,我们定义一个指令,判断当前的项目环境,可以选择在 AppServiceProviderboot 里做这件事情:

use Illuminate\Support\Facades\Blade;

/**
 * Perform post-registration booting of services.
 *
 * @return void
 */
 public function boot()
{
       Blade::if('env', function($expression){
             return app()->environment($environment);
      })
} 

定义好后,咱使用它:

@env('local')
    // The application is in the local environment...
@else
    // The application is not in the local environment...
@endenv

是不是很简单呢 ??

上一篇下一篇

猜你喜欢

热点阅读