Laravel 文档阅读:Blade 模板

简介


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

是不是很简单呢 ??

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容