视图 && 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 表单不能发出 PUT
、PATCH
或 DELETE
请求,因此需要添加一个隐藏的 _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