Laravel Blade 模板引擎的 @section 相關指令功能強大但文檔不夠詳細,導致開發者常混淆 @yield/@section、@show/@stop/@append/@override 的差異。本文透過實例深度解析各指令行為與最佳實踐。
Blade 提供兩種定義可替換區塊的方式:
| 指令 | 可繼承擴展 | 預設內容 | 用途 |
|---|---|---|---|
@yield('name', 'default') | 否 | 支援第二參數 | 單向替換,無法用 @parent |
@section('name') ... @show | 是 | 區塊內容本身 | 雙向:可替換、可擴展 |
<!-- layout.master -->
<html>
<head>
<title>@yield('title', '預設標題')</title>
</head>
<body>
@section('content')
預設的內容
@show
</body>
</html>
<!-- home.index -->
@extends('layout.master')
@section('title')
@parent
新的標題
@stop
@section('content')
@parent
擴展的內容
@stop
@parent 無效,輸出「新的標題」(完全替換)@parent 生效,輸出「預設的內容 擴展的內容」(擴展模式)| 指令 | 輸出時機 | 後續同名區塊 | 主要用途 |
|---|---|---|---|
@show | 立即輸出並結束 | 被忽略(除非 @override) | 父版面首次定義區塊 |
@stop | 僅解析不輸出 | 覆蓋前者(預設替換模式) | 子視圖定義/覆蓋區塊 |
@append | 不輸出,累積內容 | 繼續累積 | 多次追加內容(如迴圈輸出) |
@override | 輸出並清空前序累積 | 重新開始累積 | 強制覆蓋所有前序定義 |
<!-- layout.master -->
<div id="zoneA">
@section('zoneA')
AAA
@show
</div>
<div id="zoneB">
@section('zoneB')
BBB
@stop
</div>
<div id="zoneC">
@section('zoneC')
CCC
@show
</div>
<!-- page.view -->
@extends('layout.master')
@section('zoneA')
aaa
@stop
@section('zoneB')
bbb
@stop
@section('zoneC')
ccc
@show
ccc // page.view 中 @show 立即輸出
<div class="zoneA">
aaa // 子視圖 @stop 覆蓋父版面
</div>
<div class="zoneB">
</div> // 內容丟失!全程無 @show 輸出
<div class="zoneC">
ccc // 父版面 @show 輸出
ccc // 子視圖 @show 再次輸出,破壞結構
</div>
@show,子視圖覆蓋用 @stop@show 會導致雙重輸出與結構破壞<!-- master -->
<div>
@yield('content')
</div>
<!-- subview -->
@extends('master')
@section('content')
加一行內容
@append
@section('content')
再加一行內容
@append
@section('content')
加夠了,到此為止吧
@stop
<div>
加一行內容
再加一行內容
加夠了,到此為止吧
</div>
<!-- master -->
<div>
@section('content')
加一行內容
@append
@section('content')
再加一行內容
@append
@section('content')
加夠了,結束吧
@stop
@section('content')
都不要了,我說的
@override
</div>
<div>
都不要了,我說的
</div>
<!-- layouts/app.blade.php -->
<html>
<head>
@section('meta')
<meta charset="utf-8">
@show
@yield('title', '網站標題')
</head>
<body>
@section('sidebar')
預設側邊欄
@show
<main>
@yield('content')
</main>
@section('scripts')
<script src="/app.js"></script>
@show
</body>
</html>
<!-- pages/home.blade.php -->
@extends('layouts.app')
@section('title')
@parent
- 首頁
@stop
@section('sidebar')
@parent
<a href="/latest">最新文章</a>
@stop
@section('content')
首頁專屬內容
@stop
@section('scripts')
@parent
<script src="/home.js"></script>
@stop
<!-- 父版面 -->
<ul class="nav">
@section('nav-items')
<li><a href="/">首頁</a></li>
@show
</ul>
<!-- 子視圖:動態生成選單 -->
@foreach ($menuItems as $item)
@section('nav-items')
<li><a href="{{ $item->url }}">{{ $item->name }}</a></li>
@append
@endforeach
@section('nav-items')
<li><a href="/contact">聯絡我們</a></li>
@stop
@foreach ($widgets as $widget)
@section('widget-area')
@include("widgets.{$widget->type}")
@append
@endforeach
@if ($user->isAdmin())
@section('widget-area')
@include('widgets.admin-panel')
@override
@endif
| 錯誤 | 現象 | 修正 |
|---|---|---|
| 子視圖用 @show | 內容輸出兩次、HTML 結構破壞 | 子視圖統一用 @stop 或 @append |
| 全鏈路缺少 @show | 區塊內容完全不顯示 | 父版面首次定義必須用 @show |
| @yield 區塊使用 @parent | @parent 無效果,報錯或靜默失敗 | 需擴展請用 @section 定義 |
| 巢狀 @section 邏輯混淆 | 難以預測輸出結果 | 避免巢狀,改用 @include 組合 |
Blade @section 指令體系設計精妙但需精確理解:
掌握「一條鏈路一個 @show」核心原則,配合 @parent 實現擴展而非替換,能構建清晰、可維護的模板繼承體系。實務上建議制定團隊模板規範,統一區塊命名與指令使用模式。