Blade 模板继承与布局

Laravel Blade 最强大的特性之一便是模板继承。它允许你定义一个基础布局(主模板),然后让子页面继承该布局,并填充内容区块。这种方式可以彻底告别重复的 HTML 结构,让视图代码更清晰、更易维护。

💡 核心思想: 布局文件定义页面的骨架(如 header、footer、侧边栏),子视图通过 @extends 继承布局,并使用 @section 向布局中的特定区域注入内容。

1. 定义布局文件(主模板)

布局文件通常放在 resources/views/layouts 目录下。例如,创建一个 app.blade.php 作为全站主布局。

示例:resources/views/layouts/app.blade.php


<!-- 基础布局 -->
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@yield('title', '默认标题')</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    @stack('styles')
</head>
<body>
    <header>
        @include('partials.navbar')
    </header>

    <main class="container mt-4">
        @yield('content')
    </main>

    <footer>
        © {{ date('Y') }} 我的网站
    </footer>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    @stack('scripts')
</body>
</html>
                    
🔍 关键指令:
  • @yield('content') – 定义一个内容区域,子页面将填充这里。
  • @yield('title', '默认标题') – 定义可设置默认值的区域。
  • @stack('styles') – 定义栈,允许子页面通过 @push 向其中添加内容(可用于追加 CSS/JS)。

2. 子页面继承布局

子视图使用 @extends 指定要继承的布局,然后用 @section 包裹要填充到布局中对应区域的内容。

示例:关于页面 (about.blade.php)


@extends('layouts.app')

{{-- 设置页面标题 --}}
@section('title', '关于我们')

{{-- 填充 content 区域 --}}
@section('content')
    <h1>关于我们</h1>
    <p>这是关于页面的内容。</p>
@endsection

{{-- 向 styles 栈添加额外样式 --}}
@push('styles')
    <style>
        .about-page { background-color: #f0f8ff; }
    </style>
@endpush
                    

最终渲染时,Blade 会将 about.blade.php 中的内容合并到布局文件对应的位置,生成完整的 HTML。

3. 保留父级内容:@parent

有时子页面想追加内容到某个区域,而不是完全覆盖。可以使用 @parent 指令在子视图中包含父级该区域的内容。

布局中定义默认内容:


@section('sidebar')
    <div class="default-sidebar">
        <p>这是默认侧边栏</p>
    </div>
@show  {{-- 相当于 @yield 和 @section 的简写 --}}
                    

子页面继承并追加:


@section('sidebar')
    @parent  {{-- 先输出父级内容 --}}
    <div class="extra-content">
        <p>额外添加的侧边栏内容</p>
    </div>
@endsection
                    

4. 多层继承

布局也可以继承另一个布局,形成多层继承链。例如,可以有一个基础布局 base.blade.php,然后 app.blade.php 继承它,再让具体页面继承 app.blade.php。这样能更好地抽象公共部分。

5. 管理脚本与样式:@stack@push

@stack 定义栈的位置,子视图通过 @push 将内容压入栈中。这比 @yield 更适合需要多次添加内容的场景。

布局中使用栈:


<head>
    @stack('styles')
</head>
<body>
    @stack('scripts')
</body>
                    

子视图中推入内容:


@push('styles')
    <link href="/css/custom.css" rel="stylesheet">
@endpush

@push('scripts')
    <script src="/js/custom.js"></script>
@endpush
                    

如果希望推入的内容在多个地方出现,可以使用 @prepend 将内容添加到栈的开头。

6. 实战示例:博客布局

让我们构建一个博客专用的布局 blog.blade.php,它继承自主布局,并额外添加博客特有的侧边栏。

blog.blade.php


@extends('layouts.app')

@section('content')
    <div class="row">
        <div class="col-md-8">
            @yield('blog-content')
        </div>
        <div class="col-md-4">
            @include('partials.blog-sidebar')
        </div>
    </div>
@endsection

@push('styles')
    <link href="/css/blog.css" rel="stylesheet">
@endpush
                    

文章详情页 (post.blade.php)


@extends('layouts.blog')

@section('blog-content')
    <h1>{{ $post->title }}</h1>
    <div class="post-body">
        {{ $post->content }}
    </div>
@endsection

@section('title', $post->title)
                    

7. 最佳实践与常见陷阱

  • 避免过度嵌套: 一般保持 2~3 层继承即可,过深会增加维护难度。
  • 明确命名约定: 布局文件建议放在 layouts/ 目录,并以清晰名称命名(如 app.blade.phpadmin.blade.php)。
  • 使用 @show 替代 @yield 在布局中定义带默认内容的区域时,@section('sidebar') ... @show 比单独写 @yield 更直观。
  • 区分 @yield@stack 如果某个区域需要被多个子视图追加内容,使用栈;如果只是单一内容区块,用 yield。
  • 缓存影响: Blade 模板会被缓存,修改后通常无需手动清除(Laravel 会自动检测),但在生产环境使用 php artisan view:clear 可清除缓存。
📖 延伸阅读: 官方文档中关于 Blade 布局 的部分提供了更高级的用法,如动态组件和匿名组件。建议结合官方文档深入学习。