Laravel 學習筆記(12) - Blade 樣板系統

Blade

Laravel 使用 Blade 樣板系統,所有的 Blade 樣板都要以 .blade.php 結尾。
在「微型部落格」專案中,我們一共建立了 4 個 view:
  • home.blade.php
  • create.blade.php
  • edit.blade.php
  • show.blade.php
我們可以抽離共有的部份,這樣不僅維護容易,也可以少掉許多重覆的 HTML。這裡還會說明如何使用資料夾來分類 view,這樣當你的網站變大時,才會容易管理檔案。

Layout

首先在 app/views 下新增一個資料夾,名為 site,要用來放"前端"網頁的 view。

建議的作法:
  • site 放前端的 view
  • admin 放後端的 view
這只是建議,你可以依自己喜好調整。

在 site 下新增一個 layouts 資料夾,並在其中新增一個檔案 default.blade.php (app/views/site/layouts/default.blade.php):
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ $title }}</title>
</head>
<body>
    @section('sidebar')
        這是側選單
    @show

    <div class="container">
        @yield('content')
    </div>

    @include('site.layouts.footer')
</body>
</html>

@section ... @show

代表一個區段,我們給這個區段一個名稱 sidebar,表示要放側選單的內容。你可以在這個區段中加入 HTML,而在繼承它的子樣板中,可以重新定義(即覆蓋)這個區段的內容。

@yield

表示一個交由繼承它的子樣板定義的區段,如果子樣板未定義,就不會顯示任何內容。

@include

目前這個樣板可以包含其他的"片段樣板",片段樣板不會有完整的 HTML,而是代表某個部份的 HTML 片段。它被包含進這個主樣板中,屬於這個主樣板。

簡單的說,include 像是把主樣板切成幾個部份,把它分開放在幾個外部檔案中。而 section 和 yield 則是在主樣板上先挖幾個洞,section 已經放了一些東西在洞裡,yield 則是準備放東西進來。

現在把原本的 blade 檔移到 site 目錄下:
  • app/views/site/home.blade.php
  • app/views/site/create.blade.php
  • app/views/site/edit.blade.php
  • app/views/site/show.blade.php
並新增一個 footer.blade.php 在 layouts 中 (app/views/site/layouts/footer.blade.php):
<footer>
    Powered by Laravel
</footer>
在 default.blade.php 中
@include('site.layouts.footer')
. 來指定 app/views 下的目錄,所以 site.layouts.footer 意思是 (app/views)/site/layouts/footer.blade.php ,接下來就要把原本的 4 個頁面套用 default 樣板。

但是這裡要先修改 app/controllers/HomeController.php 中有關 view 的部份:
View::make('home')      改為 View::make('site.home')
View::make('create')    改為 View::make('site.create')
View::make('show')      改為 View::make('site.show')
View::make('edit')      改為 View::make('site.edit')

套用樣板

app/views/site/home.blade.php 修改如下:
@extends('site.layouts.default')

@section('content')
    <h1>{{ $title }}</h1>
    <div>{{ link_to('post/create', '新增') }}</div>
    @if (isset($posts))
        <ol>
        @foreach ($posts as $post)
            <li>
            {{-- HTML::linkRoute('post.show', $post->title, ['id'=>$post->id]) --}}
            {{ HTML::link('post/'.$post->id, $post->title) }}
            ({{ HTML::link('post/'.$post->id.'/edit', '編輯') }})</li>
        @endforeach
        </ol>
    @endif
@stop
樣板切割手術,首先把 body 之外的東西刪除,只保留 body 內的東西,接著在最上方加入:
@extends('site.layouts.default')
@extends 表示要繼承哪個樣板,這裡當然是我們前面建立的 default.blade.php。

然後把原本 body 包住的部份改為用 @section('content') ... @stop 來包住。這裡的 'content' 名稱要和 default.blade.php 中的 @yield('content') 相同,表示要填補這個洞。

現在可以看看原本的 post 頁面,應該會在上面多出"這是側選單";下面多出"Powered by Laravel" 的文字,這些都是在 default 中設定的。其他 3 個頁面修改方法都一樣,請自行修改。

你可以自己試試看增加一個
@section('sidebar')
    xxx
@stop
區段,你會發現原本 default 中的 sidebar 區段被取代了。一個 blade 檔中,可以有多個 @section ... @stop 區塊。

樣板架構控制

輸出

3 種 echo 方法:
  • @{{ ... }}:blade 不執行 echo,直接顯示 @ 符號後的內容。
  • {{ ... }}:HTML有效的輸出。
  • {{{ ... }}}:HTML無效的輸出。
範例:
@{{ '111' }}
{{ '<h1>222</h1>' }}
{{{ '<h1>333</h1>' }}}
結果:
{{ '111' }}
222 (註:這裡會依h1的樣式顯示)
<h1>333</h1>

條件控制

@if (isset($title))
    ...
@endif
@if (isset($title))
    ...
@elseif(isset($content))
    ...
@else
    ...
@endif
或(除非為真)
@unless (isset($title))
    ...
@endunless
isset() 是 PHP 的函式。其實這些@開頭的敍述最後都會被 Blade 轉成 PHP。本質上還是 PHP,只是用一個比較簡潔的方式表達。

重覆執行

@for ($i = 0; $i < 10; $i++)
    第 {{ $i }} 圈。
@endfor
或之前我們用過的
@foreach ($posts as $post)
    {{ $post->id }}
@endforeach

註解

{{-- 這是註解,不會產生 HTML 碼 --}}

載入 CSS、Javascript 及圖檔

還有一個一定需要的功能,CSS、Javascript 及圖檔要怎麼處理呢?

1.首先是檔案要放哪裡?

這些檔案要放在 public 目錄中,這個目錄不在 app 目錄之下,而是和它同一層。我們可以建立一個 css 目錄、js 目錄及 img 目錄,分別放不同類型的檔案。例如:
  • public/css
  • public/js
  • public/img

2.如何使用這些檔案?

在 view 中,使用 HTML 類別的方法來載入。
CSS
{{ HTML::style('css/site/main.css') }}
Javascript
{{ HTML::script('js/jquery.min.js') }}
圖檔
{{ HTML::image('img/logo.png') }}
本文網址:http://blog.tonycube.com/2015/01/laravel-12-blade.html
Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀

14 則留言

  1. 你好,
    我嘗試了一下
    {{ '<h1>222</h1>' }}
    但是和你說的不太一樣捏

    我後來參考了官方文件,推測應該是這個原因
    https://laravel.tw/docs/5.2/blade
    ---
    顯示未跳脫的資料

    在預設情況下,Blade 模板中的 {{ }} 表達式將會自動套用 PHP 的 htmlentities 函式,以避免 XSS 攻擊。如果你不希望你的資料被跳脫,可以使用下列的語法:
    Hello, {!! $name !!}.
    ---

    所以,如果要能顯示 h1 的效果
    應該會需要用這樣的方法:
    {!! '<h1>222</h1>' !!}

    如果我有任何說錯的再麻煩你告訴我唷^^

    回覆刪除
    回覆
    1. 你說的沒錯~~
      我的文章是4.x版的,5.2版的如官方文件所說
      {{ ... }} 會把 HTML 的角標籤轉成文字,所以就不會有HTML的任何效果
      {!! ... !!} 應該是新的語法,設計者應該是很怕你亂用被攻擊,所以故意左右各加兩個問號來確定你是不是要輸出可被瀏覽器解讀的 html

      刪除
  2. 你好,我問一個問題{{ HTML::style('css/site/main.css') }}在laravel5.3板還有這樣的寫法嗎

    回覆刪除
    回覆
    1. 你可以裝 laravelcollective/html 這個套件
      https://laravelcollective.com/docs/5.3/html
      就能用同樣的寫法

      不過在 5.3 你也可以直接這麼寫
      <link rel="stylesheet" href="{{ asset('css/site/main.css') }}">

      刪除
  3. @section ... @show
    @section ... @stop

    兩者的差異 可否請版大說明....

    回覆刪除
    回覆
    1. 在執行到 @show 時,會將內容輸出到頁面中,
      而 @stop 則解析內容後回傳結果,並且終止後續的處理。

      @show 可以被覆蓋;@stop 不行,它就是終點。

      在第一次定義區塊時,如果要保留可以被覆蓋,會用 @show,
      所以你會看到在 layout 檔中,會用 @show
      然後在其他使用 @extends 繼承該 layout 的樣板中,
      才使用 @stop 把 @show 蓋掉並終止。

      參考資料:http://www.jb51.net/article/60957.htm

      刪除
  4. 請問 若我有一群js 或css 在很多頁面都用到 是不是 將該群 js 做成jsall.blad.php 然後用include 該檔案 就可以一次放進來 多次include 不同群的js群好 還是只在index用@parents 一個個引進到default頁面 這兩者有差別嗎?

    回覆刪除
    回覆
    1. 通常會把共用到的 js/css 放在 default 頁面,其他頁面需要額外的 js/css 則放在自己的頁面中,不會單獨把 js/css 放在一個頁面來載入。現代的瀏覽器都有暫存的功能,也就是載入過的相同檔案不會再次下載,所以即使放在 default 頁面的 js/css 在某些頁面用不到,也會因為它已在載入 default 頁面時就已經快取在瀏覽器中,而不會影響效能。

      如果你用的是 Laravel 5.4 以後的版本,它有提供 Mix 把 js 打包成一個檔案的功能,可以把共用的套件打包成一個檔,各自頁面的 js 打包成一個檔。相關內容可以參考 http://blog.tonycube.com/2017/06/vuejs11-laravel-vue.html

      刪除
  5. 您好~~

    請問如果今天要在一個 XX.blade.php 檔案當中引入 Vue Component 一定要透過 @yield('content') 把 Vue Component 裝載到 這個 content 嗎?

    可不可以直接透過 XX.blade.php 這個 container(容器) 去裝載我們建立的 Vue Component?
    謝謝!

    回覆刪除
    回覆
    1. 另外想請教第二個問題,在 XX.blade.php當中

      可以寫html(這在另一篇文章您有提及過

      那在XX.blade.php當中我可以同時寫htmp又寫blade模板的東西嗎,像是我要載入 banner 所以寫了

      @extends('banner.blade.php')

      謝謝。

      刪除
    2. 通常你會在共用的 layout 中用 @yield 讓其他樣板可以自訂內容,如果你的樣板本身不打算讓其他樣板載入的話,就不需要 @yield ,和你在哪裡用 Vue Component 沒什麼關係。

      @extends 是繼承或擴充的意思,等於你把 banner.blade.php 擴充,感覺不太對,你應該是用 @include 載入某個獨立片段,例如 banner.blade.php 這樣比較符合

      刪除
  6. 好的!!謝謝糾正與指教!!

    回覆刪除
  7. 您好~想請問一下!
    可以能夠一個模板同時引入create跟Show的頁面嗎?
    我自己寫得每次都變成一次四個頁面都引入了@@"

    回覆刪除
    回覆
    1. 可以建立多個 @section 區塊一個放 create 一個放 show

      刪除

留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。