视图 && blade模板引擎

Blade 是由 Laravel 提供的非常简单但功能强大的模板引擎,不同于其他流行的 PHP 模板引擎,Blade 在视图中并不约束你使用 PHP 原生代码。所有的 Blade 视图最终都会被编译成原生 PHP 代码并缓存起来直到被修改,这意味着对应用的性能而言 Blade 基本上是零开销。Blade 视图文件使用 .blade.php 文件扩展并存放在 resources/views 目录下。

创建 & 渲染视图

直接从路由和控制器返回整个 HTML 文档字符串是不实际的,视图提供了一种方便的方法,可以将所有的 HTML 放在不同的文件中。视图将控制器 / 应用逻辑与显示逻辑分开,并存储在 resources/views 目录下。一个简单的视图如下所示

<!-- 本段代码存储在 resources/views/greeting.blade.php -->

<html>
    <body>
        <h1>Hello, {{ $name }}</h1>
    </body>
</html>

将上述代码存储在 resources/views/greeting.blade.php 后,我们可以使用全局辅助函数 view 将其返回,如下所示

Route::get('/', function () {
    return view('greeting', ['name' => 'James']);
});

也可以使用 View facade 返回视图

use Illuminate\Support\Facades\View;

return View::make('greeting', ['name' => 'James']);

视图也可以嵌套在 resources/views 目录的子目录中。. 符号可用于引用嵌套视图。例如,如果你的视图存放在 resources/views/admin/profile.blade.php,你可以在应用的路由或者控制器中使用如下所示方法返回视图

return view('admin.profile', $data);

向所有视图分享数据

有时候,你可能需要共享一段数据给应用程序的所有视图。你可以使用 View facade 的 share 方法来实现。通常情况下,你可以在服务提供器的 boot 方法中调用 share 方法。你可以把他们添加到 App\Providers\AppServiceProvider 类,或者为它们生成一个单独的服务提供器

<?php

namespace App\Providers;

use Illuminate\Support\Facades\View;

class AppServiceProvider extends ServiceProvider
{
    /**
     * 注册应用服务
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * 引导应用服务
     *
     * @return void
     */
    public function boot()
    {
        View::share('key', 'value');
    }
}

blade模板引擎

在blade模板输出函数

The current UNIX timestamp is {{ time() }}.

展示非转义数据

要输出带 HTML 元素的富文本,可以使用如下语法

Hello, {!! $name !!}.

渲染 JSON

有时,您可能会将数组传递给视图,以将其呈现为 JSON,以便初始化 JavaScript 变量。 例如

<script>
    var app = <?php echo json_encode($array); ?>;
</script>

也可以使用 @json Blade 指令来代替手动调用 json_encode 方法。 @json 指令的参数和 PHP 的 json_encode 函数一致

<script>
    var app = @json($array);

    var app = @json($array, JSON_PRETTY_PRINT);
</script>

Blade & JavaScript 框架

由于许多 JavaScript 框架也使用「花括号」来标识将显示在浏览器中的表达式,因此,可以使用 @ 符号来表示 Blade 渲染引擎应当保持不变。例如

<h1>Laravel</h1>

Hello, @{{ name }}.

在这个例子中, @ 符号将被 Blade 移除;当然,Blade 将不会修改 {{ name }} 表达式,取而代之的是 JavaScript 模板来对其进行渲染

{{-- Blade 模板 --}}
@@json()

<!-- HTML 输出 -->
@json()

@verbatim 指令

@verbatim
    <div class="container">
        Hello, {{ name }}.
    </div>
@endverbatim

Blade 指令

除了模板继承和显示数据以外, Blade 还为常见的 PHP 控制结构提供了便捷的快捷方式,例如条件语句和循环。这些快捷方式为 PHP 控制结构提供了一个非常清晰、简洁的书写方式,同时,还与 PHP 中的控制结构保持了相似的语法特性

If 语句
@if (count($records) === 1)
    // 有一条记录
@elseif (count($records) > 1)
    // 多条记录
@else
    // 没有记录
@endif

为了方便, Blade 还提供了一个 @unless 指令

@unless (Auth::check())
    // 还没有登录
@endunless

相当于 @if (! Auth::check()) @endif

除了上面所说条件指令外, @isset 和 @empty 指令亦可作为它们所对应的 PHP 函数的快捷方式

@isset($records)
    // $records 已经被定义且不为 null ……
@endisset

@empty($records)
    // $records 为「空」……
@endempty
授权指令

@auth 和 @guest 指令可用于快速判断当前用户是否已经获得 授权 或是游客:

@auth
    // 用户已经通过认证……
@endauth

@guest
    // 用户没有通过认证……
@endguest

如有需要,也可在使用 @auth 和 @guest 指令时指定鉴权守卫:

@auth('admin')
    // 用户已经通过认证……
@endauth

@guest('admin')
    // 用户没有通过认证……
@endguest
环境指令

可以使用 @production 指令来判断当前应用是否处于生产环境:

@production
    // 生产环境执行的逻辑语句……
@endproduction

或者,您可以使用 @env 指令确定应用程序是否在特定环境中运行:

@env('staging')
    // 该应用运行在 「staging」 环境中...
@endenv

@env(['staging', 'production'])
    // 该应用运行在 「staging」和 「production」 环境中...
@endenv
hasSection 指令
您可以使用 `@hasSection` 指令确定模板继承节是否包含内容:

@hasSection('navigation')
    <div class="pull-right">
        @yield('navigation')
    </div>

    <div class="clearfix"></div>
@endif

你可以使用 @sectionMissing 指令来确定节是否没有内容

@sectionMissing('navigation')
    <div class="pull-right">
        @include('default-navigation')
    </div>
@endif
Switch 语句
@switch($i)
    @case(1)
        第一个用例 ...
        @break

    @case(2)
        第二个用例 ...
        @break

    @default
        其他用例 ...
@endswitch
循环
@for ($i = 0; $i < 10; $i++)
    当前的值是 {{ $i }}
@endfor

@foreach ($users as $user)
    <p>这是 {{ $user->id }} 用户</p>
@endforeach

@forelse ($users as $user)
    <li>{{ $user->name }}</li>
@empty
    <p>没有用户</p>
@endforelse

@while (true)
    <p>我正在循环,直到天荒地老</p>
@endwhile

使用循环时,还可以使用 @continue 和 @break 指令结束循环或跳过当前循环

@foreach ($users as $user)
    @if ($user->type == 1)
        @continue
    @endif

    <li>{{ $user->name }}</li>

    @if ($user->number == 5)
        @break
    @endif
@endforeach
循环变量

循环时,可以在循环内使用 $loop 变量将在你的循环中可用。这个变量提供了一些有用的信息,比如当前循环的索引,以及这是循环的第一次还是最后一次迭代

@foreach ($users as $user)
    @if ($loop->first)
        这是第一次迭代。
    @endif

    @if ($loop->last)
         这是最后一个迭代。
    @endif

    <p>This is user {{ $user->id }}</p>
@endforeach

如果你在一个嵌套循环中,你可以通过 parent 属性访问父循环的 $loop 变量

@foreach ($users as $user)
    @foreach ($user->posts as $post)
        @if ($loop->parent->first)
            这是父循环的第一次迭代。
        @endif
    @endforeach
@endforeach

$loop 变量还包含了其他一些有用的属性

属性 描述
$loop->index 当前循环迭代的索引 (从 0 开始)。
$loop->iteration 在当前循环迭代时 (从 1 开始)。
$loop->remaining 循环中剩余的迭代。
$loop->count 数组中被迭代项的总个数。
$loop->first 这是否是循环的第一次迭代。
$loop->last 这是否是循环的最后一次迭代。
$loop->even 这是否是循环中的偶数迭代。
$loop->odd 这是否是循环中的奇数次迭代。
$loop->depth 当前循环的嵌套级别。
$loop->parent 在嵌套循环中,父循环变量。
注释
{{-- 这个注释将不会显示在 HTML 中 --}}
引入子视图

Blade 的 @include 指令允许您从一个视图中包含另外一个 Blade 视图。父视图中的所有变量在子视图中都可以使用

<div>
    @include('shared.errors')

    <form>
        <!-- 表单内容 -->
    </form>
</div>

子视图可以继承父视图中所有可以使用的数据,但是您也可以传递一个额外的数组,这个数组在子视图中也可以使用:

@include('view.name', ['status' => 'complete'])

注意:在视图中,您应该避免使用 __DIR____FILE__ 这些常量,因为他们将引用已缓存的和已编译的视图.

组件布局

定义布局组件

<!-- resources/views/components/layout.blade.php -->

<html>
    <head>
        <title>{{ $title ?? 'Todo Manager' }}</title>
    </head>
    <body>
        <h1>Todos</h1>
        <hr/>
        {{ $slot }}
    </body>
</html>

应用布局组件

<!-- resources/views/tasks.blade.php -->
// 使用布局组件
<x-layout>
    // 使用title插槽
    <x-slot name="title">
        Custom Title
    </x-slot>

    @foreach ($tasks as $task)
        {{ $task }}
    @endforeach
</x-layout>

现在我们已经定义了布局和任务列表视图,我们只需要从路由中返回 task 视图即可

use App\Models\Task;

Route::get('/tasks', function () {
    return view('tasks', ['tasks' => Task::all()]);
});

模板继承

定义一个布局

<!-- resources/views/layouts/app.blade.php -->

<html>
    <head>
        <title>App Name - @yield('title')</title>
    </head>
    <body>
        // 定义内容的一部分
        @section('sidebar')
            这是一个主要的侧边栏
        @show

        <div class="container">
            {{-- 用于显示给定部分的内容 --}}
            @yield('content')
        </div>
    </body>
</html>

继承布局

<!-- resources/views/child.blade.php -->

// 继承模板布局
@extends('layouts.app')

// 将内容注入模板布局的节点中
@section('title', 'Page Title')

@section('sidebar')
    // 将内容追加(而不是覆盖)到局部的侧栏位置
    @parent

    <p>This is appended to the master sidebar.</p>
@endsection

// 把这些部分的内容在模板布局显示
@section('content')
    <p>This is my body content.</p>
@endsection

表单

CSRF 字段

在laravel中定义 HTML 表单,都应该在表单中包含一个隐藏的 CSRF 令牌字段,以便 CSRF 保护中间件 可以验证请求。你可以使用 @csrf Blade 指令生成令牌字段

<form method="POST" action="/profile">
    @csrf

    ...
</form>

Method 字段

于 HTML 表单不能发出 PUTPATCHDELETE 请求,因此需要添加一个隐藏的 _method 字段来欺骗这些 HTTP 动词。@method Blade 指令可以为你创建此字段

<form action="/foo/bar" method="POST">
    @method('PUT')

    ...
</form>

表单校验错误

@error 指令可用于快速检查给定属性是否存在 验证错误消息 。在 @error 指令中,可以回显 $message 变量以显示错误消息

<label for="title">Post Title</label>

<input id="title" type="text" class="@error('title') is-invalid @enderror">

@error('title')
    <div class="alert alert-danger">{{ $message }}</div>
@enderror

你可以将 特定错误包的名称 作为第二个参数传递给 @error 指令,以便在包含多个表单的页面上检索验证错误消息

<label for="email">Email address</label>

<input id="email" type="email" class="@error('email', 'login') is-invalid @enderror">

@error('email', 'login')
    <div class="alert alert-danger">{{ $message }}</div>
@enderror

原生 PHP

在某些情况下,将 PHP 代码嵌入到视图中是很有用的。您可以使用 Blade @php 指令在模板中执行一个普通 php 语句:

@php
    $counter = 1;
@endphp

堆栈

Blade 可以被推送到在其他视图或布局中的其他位置渲染的命名堆栈。这在子视图中指定所需的 JavaScript 库时非常有用:

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

可以根据需要多次推入堆栈。要呈现完整的堆栈内容,请将堆栈的名称传递给 @stack 指令

<head>
    <!-- Head Contents -->

    @stack('scripts')
</head>

如果要将内容前置到堆栈的开头,应使用 @prepend 指令

@push('scripts')
    这是第二加载的...
@endpush

// Later...

@prepend('scripts')
    这是第一加载的...
@endprepend
powered by GitbookEdit Time: 2023-04-08 10:28:32