Laravel Blade 最强大的特性之一便是模板继承。它允许你定义一个基础布局(主模板),然后让子页面继承该布局,并填充内容区块。这种方式可以彻底告别重复的 HTML 结构,让视图代码更清晰、更易维护。
@extends 继承布局,并使用 @section 向布局中的特定区域注入内容。
布局文件通常放在 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)。
子视图使用 @extends 指定要继承的布局,然后用 @section 包裹要填充到布局中对应区域的内容。
@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。
@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
布局也可以继承另一个布局,形成多层继承链。例如,可以有一个基础布局 base.blade.php,然后 app.blade.php 继承它,再让具体页面继承 app.blade.php。这样能更好地抽象公共部分。
@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 将内容添加到栈的开头。
让我们构建一个博客专用的布局 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
@extends('layouts.blog')
@section('blog-content')
<h1>{{ $post->title }}</h1>
<div class="post-body">
{{ $post->content }}
</div>
@endsection
@section('title', $post->title)
layouts/ 目录,并以清晰名称命名(如 app.blade.php、admin.blade.php)。@show 替代 @yield: 在布局中定义带默认内容的区域时,@section('sidebar') ... @show 比单独写 @yield 更直观。@yield 与 @stack: 如果某个区域需要被多个子视图追加内容,使用栈;如果只是单一内容区块,用 yield。php artisan view:clear 可清除缓存。