视图与Blade模板:视图创建与渲染、Blade模板引擎、模板继承与布局、组件与插槽、@include与@each指令

好,咱们今天来聊聊Laravel里最让我觉得「舒服」的部分——视图和Blade模板。

说实话,我最早接触PHP框架时,最头疼的就是HTML和PHP代码混在一起写。那叫一个乱。直到用了Laravel的Blade,我才觉得「嗯,这才对嘛」。

视图创建与渲染

视图是什么?说白了就是展示给用户看的页面。

在Laravel里,视图文件放在 resources/views 目录下。我习惯按模块分文件夹,比如 admin/user/,这样找起来方便。

创建一个视图很简单。新建一个 .blade.php 文件就行:

<!-- resources/views/welcome.blade.php -->
<!DOCTYPE html>
<html>
<head>
    <title>我的第一个Blade视图</title>
</head>
<body>
    <h1>欢迎来到我的网站</h1>
</body>
</html>

然后在控制器里返回它:

public function index()
{
    return view('welcome');
}

如果你放在子文件夹里,用点号分隔:

return view('admin.dashboard');

传数据给视图也很自然。我常用第二种写法:

// 方式一:with方法
return view('profile')->with('name', $name);

// 方式二:第二个参数传数组(我个人偏爱这个)
return view('profile', ['name' => $name, 'age' => 25]);

// 方式三:compact函数(最简洁)
return view('profile', compact('name', 'age'));
小技巧:我习惯在控制器里用 compact(),少写几个字,看着也清爽。但变量名必须和视图里用的一致,别搞混了。

Blade模板引擎

Blade是Laravel自带的模板引擎。它不限制你在视图里写原生PHP,但提供了很多语法糖。

输出变量用双花括号:

<p>你好,{{ $name }}</p>

它会自动转义HTML,防止XSS攻击。如果你需要输出原生HTML(比如富文本内容),用 {!! !!}

<p>{!! $content !!}</p>
注意:{!! !!} 时要确保数据是安全的。我曾经有个项目因为没注意这个,被注入了恶意脚本,排查了好久。从那以后,我只有确认数据来源可靠时才用。

控制结构也很简洁。比如条件判断:

@if (count($users) > 0)
    <p>有 {{ count($users) }} 个用户</p>
@else
    <p>暂无用户</p>
@endif

循环:

@foreach ($users as $user)
    <li>{{ $user->name }}</li>
@endforeach

你想想看,这比在HTML里写 <?php foreach(...): ?> 舒服多了吧?

模板继承与布局

这是Blade最强大的功能之一。我几乎每个项目都会用。

先创建一个布局文件 layouts/app.blade.php

<!DOCTYPE html>
<html>
<head>
    <title>@yield('title', '默认标题')</title>
    <link rel="stylesheet" href="/css/app.css">
</head>
<body>
    <header>
        @include('partials.nav')
    </header>

    <main>
        @yield('content')
    </main>

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

然后子视图继承它:

@extends('layouts.app')

@section('title', '用户列表')

@section('content')
    <h1>所有用户</h1>
    @foreach ($users as $user)
        <p>{{ $user->name }}</p>
    @endforeach
@endsection

这样,所有页面的头部和尾部都统一了。改一处,全站跟着变。

核心思路:布局文件定义「骨架」,子视图填充「血肉」。我见过很多新手在每个页面里重复写导航栏和页脚,那简直是灾难。

组件与插槽

组件比模板继承更灵活。你可以把一段可复用的UI封装起来。

创建一个组件 resources/views/components/alert.blade.php

<div class="alert alert-{{ $type }}">
    {{ $slot }}
</div>

使用它:

<x-alert type="success">
    操作成功完成!
</x-alert>

如果有多个插槽,用命名插槽:

<!-- components/card.blade.php -->
<div class="card">
    <div class="card-header">
        {{ $header }}
    </div>
    <div class="card-body">
        {{ $slot }}
    </div>
</div>
<x-card>
    <x-slot name="header">
        用户信息
    </x-slot>
    <p>姓名:张三</p>
    <p>邮箱:zhang@example.com</p>
</x-card>
我的习惯:如果一段UI在三个以上页面出现,我就把它做成组件。比如按钮、弹窗、表单输入框。这样后期改样式,改一个文件就行。

@include与@each指令

@include 用来引入一个子视图。适合拆分重复的小片段。

@include('partials.user-card', ['user' => $user])

被引入的视图可以直接使用传入的变量:

<!-- partials/user-card.blade.php -->
<div class="user-card">
    <h3>{{ $user->name }}</h3>
    <p>{{ $user->email }}</p>
</div>

@each@include 的循环版本。我坦白说,这个指令我用得不多,但某些场景下确实方便:

@each('partials.user-card', $users, 'user', 'partials.empty')

四个参数分别是:视图名称、数据集合、每次迭代的变量名、没有数据时显示的视图。

避坑指南:我曾经在循环里用 @include 加载大量子视图,结果页面加载慢得像蜗牛。后来发现是每个子视图里都做了数据库查询。记住,视图里尽量别做复杂逻辑,数据提前在控制器里准备好。

好了,关于视图和Blade模板,核心内容就这些。总结一下:

  • 视图放在 resources/views,用 view() 返回
  • Blade用 {{ }} 输出,用 @if@foreach 做控制
  • 模板继承用 @extends@yield,适合整体布局
  • 组件用 <x-> 语法,适合复用小块UI
  • @include 引入子视图,@each 批量引入

你把这些练熟了,Laravel的前端部分基本就拿下了一大半。下一章咱们聊聊更进阶的东西。