Laravel 文檔閱讀:Blade 模板

簡介


Blade 是 Laravel 提供的模板引擎,它簡單強(qiáng)大。不像其他的 PHP 模板引擎,Blade 允許在視圖中使用原生 PHP 代碼。實(shí)際上,所有的 Blade 視圖最終都會被編譯成原生 PHP 代碼,緩存在 storage/framework/views 文件夾中。Laravel 使用的是這些編譯后的緩存文件,而不是視圖本身,所以,Blade 對于應(yīng)用程序來說是零開銷的。當(dāng)你修改了視圖文件,那么它會重新編譯并緩存,以便使用。Blade 視圖以 blade.php 為后綴名,一般存放于 resources/views 文件夾中。

模板繼承


定義布局文件

Blade 模板引擎的主要兩個優(yōu)點(diǎn)是 “模板繼承” 和 “區(qū)塊”。舉一個簡單的例子,一個項目里,幾乎所有的頁面都是一樣的布局,這時候就可以把這個布局提煉出來,作為母版頁,繼承了這個母版頁的的頁面都有一樣的布局效果,成為母版頁的子頁。母版頁還叫布局文件,布局文件就是一個 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>

布局文件里除了基礎(chǔ)的 HTNL 標(biāo)簽,還使用了兩個指令:@section@yield 。@section定義區(qū)塊,@yield 定義區(qū)塊里的內(nèi)容。
下面。來定義布局文件的子頁。

繼承布局文件

子頁中,使用 Blade 的 @extends 指令指定 “繼承” 的布局文件,使用 @section 指令為在布局文件中使用 @section@yield 指令的地方注入內(nèi)容:

<!-- 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 注入內(nèi)容;在布局文件中使用 @section 指令定義的一個好處是:在子頁中使用 @section 注入時,可以使用 @parent 指令附加(而非重寫)在布局文件中的內(nèi)容,而在布局文件中使用 @yield 指令定義的地方是做不到的。@parent 指令會在視圖渲染的時替換成布局文件里的內(nèi)容。
注意,與在文件布局里定義的 sidebar 不同的是,子頁里使用 @endsection 結(jié)束,而非 @show 。因?yàn)?@endsection 僅用來定義區(qū)塊,而 @show 是用來定義、立馬產(chǎn)出區(qū)塊的。
從路由中直接返回視圖文件,要用到全局輔助函數(shù) helper :

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

組件&插槽


組件和插槽提供了類似布局和區(qū)塊的優(yōu)點(diǎn)。而組件和插槽的心智模型更符合直覺。設(shè)想一下,在我們的項目中有一個可重復(fù)的 “彈框” 組件:

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

{{ $slot }} 表示插入組建的內(nèi)容。構(gòu)建此組件,是使用 Blade 的@component指令:

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

在這個場景里,{{ $slot }} 變量的內(nèi)容是:

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

有時一個組件需要多個插槽。這時,只需要稍改組件代碼,定義一個 “標(biāo)題” 插槽,這個插槽稱命名插槽。命名插槽是通過簡單的 “打印” 匹配其名稱的變量來顯示內(nèi)容的:

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

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

為名名插槽注入內(nèi)容,使用 @slot 指令。所有不在 @slot 指令里的內(nèi)容都會傳遞給組件里的 $slot 變量。

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

為組建傳遞額外數(shù)據(jù):

有時需要為組建件遞額外數(shù)據(jù)。為此,可以為 @conponent 指令傳遞第二個數(shù)組參數(shù)。指定要傳遞的額外。據(jù)所有過去的額外數(shù)據(jù)作為變量,在組件模板里都可以取的:

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

顯示數(shù)據(jù)

向 Blade 視圖傳遞數(shù)據(jù),是通過將變量包裹在 [ ] 里實(shí)現(xiàn)的:

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

下面就可以使用 name 變量顯示內(nèi)容了:

Hello! {{ $name }}

{{ }} 是 Blade 視圖的打印語句,當(dāng)然,打印語句里不限制只能打印變量內(nèi)容,也可以使用 PHP 函數(shù)。實(shí)際上,打印語句這里可以使用任何 PHP 代碼:

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

顯示非轉(zhuǎn)移數(shù)據(jù)

默認(rèn),所有傳遞給 Blade {{ }} 語句的內(nèi)容都會使用 htmlspecialchar 函數(shù)處理、將內(nèi)容轉(zhuǎn)義,避免 XSS 攻擊。如果無需轉(zhuǎn)義輸出的內(nèi)容,可以使用下面語法:

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

不過千萬要小心,應(yīng)該優(yōu)先選擇使用轉(zhuǎn)義的 {{ }} 語法避免 XXS 攻擊。因?yàn)?,有時你很難避免用戶有意的、無意的數(shù)據(jù)輸入。

Blade & JavaScript 框架

由于一些 JavaScript 框架也使用花括號 {{ }} 語法解析內(nèi)容,為了區(qū)分開 Blade 和這些用到的 JavaScript 框架,你可以使用 @ 符號來告訴 Blade 模板引擎說,這個地方不要動,保持原樣就可以了:

<h1>Laravel</h1>

Hello! @{{ $name }}

上面例子里, @ 符號會從 Blade 中刪除,而 {{ $name }} 會保持原樣,用來給你的 JavaScript 框架渲染使用。

@verbatim 指令

如果使用 JavaScript 框架渲染的模塊區(qū)域很大,這時就可以使用 @verbatim 指令包裹這些模板區(qū)域,這樣就避免了在每個Blade 打印語句前都跟上 @ 符號的麻煩:

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

控制結(jié)構(gòu)

除了模板繼承和顯示數(shù)據(jù),Blade 還未常見的 PHP 結(jié)構(gòu)提供了快捷方式,比如條件談判和循環(huán)。這些快捷方式提供了一種非常干凈、簡潔的控制結(jié)構(gòu),并且保持了原生 PHP 的形式。

if 語句

構(gòu)造 if 語句使用 @if 、@elseif 、@else 和 endif 指令。這些指令和原生 PHP 的控制功能一一對應(yīng):

@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 里的對應(yīng)功能相同:

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

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

認(rèn)證

@auth@guest 指令用來判斷當(dāng)前用戶是認(rèn)證用戶還是游客:

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

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

Switch 語句

switch 語句使用 @switch 、@case@break、@default@endswitch 指令構(gòu)建:

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

          @default
                Default case...
@endswitch

循環(huán)

Blade 還提供了循環(huán)方面的指令。再一次聲明:這里的每一個指令都與原生 PHP 里的對應(yīng)功能相同。

@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

在循環(huán)時可以結(jié)束或跳出當(dāng)前的迭代:

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

   <li>{{ $user->name }}</li>
 
   @break($user->number == 5)
@endforeach 

$loop 變量

在循環(huán)時,內(nèi)部有一個可用變量 $loop 。這個變量提供了跟循環(huán)有關(guān)的有用信息,比如當(dāng)前迭代的索引、是否是第一次、最后一次迭代等:

@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

如果是在嵌套的循環(huán)里,就可以使用 $loop 變量的 parent 屬性父級循環(huán)里的 $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 模板注釋不會出現(xiàn)在最終渲染的 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>

雖然子視圖會繼承父級視圖內(nèi)的所有變量,但是你也可以為引入的子視圖傳遞額外數(shù)據(jù),這些數(shù)據(jù)是以數(shù)組的形式傳遞過去的:

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

當(dāng)你用 @include 引入的視圖不存在時, Laravel 會拋出錯誤。如果引入的試圖不確定是否存在,應(yīng)該使用 @includeIf 指令:

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

如果要通過一個布爾值判斷是否引入子視圖,需要使用 @includeWhen 指令:

@includeWhen($boolean, 'view.name', ['some' => 'data'])

注意:不要使用 __DIR____FILE__ 常量引入 Blade 視圖,因?yàn)槌绦驅(qū)嶋H使用的是編譯后的、緩存在 storage/framework/views 文件夾中的文件。

為集合渲染視圖

@each 指令整合了循環(huán)數(shù)據(jù)和引入視圖的功能:

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

第一個參數(shù)是為數(shù)組或者集合中每個元素渲染數(shù)據(jù)時指定的視圖,第二個參數(shù)是要便利的數(shù)組或集合,第三個參數(shù)是當(dāng)前迭代的元素數(shù)據(jù)在子視圖中的變量名。在上面的例子里,我們遍歷的數(shù)組是 jobs , 在 view.name 視圖里渲染 job 變量,當(dāng)前迭代的 key 使用 key 變量獲取。
也可以為 @each 指令傳遞第四個參數(shù),這是在給定數(shù)組元素為空時渲染的視圖:

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

注意:使用 @each 渲染的視圖不從父級模板里繼承變量。如果子視圖還需要這些變量,你應(yīng)該使用 foreach@include 指令組合。

堆棧


Blade 允許你使用 @push 指令向命名堆棧里推入內(nèi)容,命令堆棧以 @stack 指令定義,可以定義在普通視圖或者布局文件里,推入的內(nèi)容會在視圖或者布局文件里渲染出來。這在為子視圖添加額外的 JavaScript 庫的場景下特別有用。

<!-- 在視圖或者布局文件里定義堆棧 -->
<head>
    <!-- Head Contents -->
    @stack('scripts')
</head>

<!-- 在子視圖中推入堆棧內(nèi)容 -->
@push('scripts')
    <script src="/example.js"></script>
@endpush

你可以盡你自己所需的多次向堆棧推入數(shù)據(jù)。

服務(wù)注入


@inject 指令可以從 Laravel 的服務(wù)提供者中獲得服務(wù)。傳遞給 @inject 指令的第一個參數(shù)是一個變量名,獲得的服務(wù)就是存放在這個變量里,第二個參數(shù)就是你要解析的服務(wù)的類名或接口名。

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

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

擴(kuò)展 Blade


Blade 允許你使用 directive 方法創(chuàng)建自定義指令。當(dāng) Blade 方法遇到自定義指令時,會將接收到的表達(dá)式 (expression)放在自定義指令的回調(diào)閉包里處理。
在下面的例子里,我們創(chuàng)建了一個 @datatime($var) 指令,$var應(yīng)該是一個DateTime 實(shí)例:

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()
     {
          //
     }
}

可以看到,我們在傳過來的表達(dá)式上使用了 format 方法。在這個例子里,@datetime($var) 指令最終生成的 PHP 代碼如下:

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

注意:在更新自定義指令后,需要刪除所有的視圖文件,可以用 view:cache Artisan 命令實(shí)現(xiàn)。

自定義 if 語句

當(dāng)自定義涉及簡單的條件判斷時,使用 Blade::directive 的方式可能會變得稍復(fù)雜些。為此, Blade 引入了 Blade::if 方法使用閉包來快速自定義條件判斷指令。例如,我們定義一個指令,判斷當(dāng)前的項目環(huán)境,可以選擇在 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

是不是很簡單呢 ??

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容