刀片模板

Introduction

Blade 是 Laravel 中包含的简单而强大的模板引擎。与某些 PHP 模板引擎不同,Blade 不限制您在模板中使用纯 PHP 代码。事实上,所有 Blade 模板都被编译成纯 PHP 代码并缓存直到它们被修改,这意味着 Blade 基本上为您的应用程序增加了零开销。刀片模板文件使用.blade.php 文件扩展名,通常存储在resources/views 目录。

刀片视图可以使用全局从路由或控制器返回view 帮手。当然,正如文档中提到的views, 数据可以使用传递到 Blade 视图view 助手的第二个参数:

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

带有 Livewire 的增压刀片

想要将您的 Blade 模板提升到一个新的水平并轻松构建动态界面?查看Laravel Livewire. Livewire 允许您编写 Blade 组件,这些组件增加了通常只能通过 React 或 Vue 等前端框架实现的动态功能,提供了一种构建现代反应式前端的好方法,而无需复杂的客户端渲染或构建步骤许多 JavaScript 框架。

显示数据

您可以通过将变量括在大括号中来显示传递给 Blade 视图的数据。例如,给定以下路线:

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

您可以显示的内容name 像这样的变量:

Hello, {{ $name }}.

Note
刀片的{{ }} echo 语句通过 PHP 自动发送htmlspecialchars 功能来防止XSS攻击。

您不限于显示传递给视图的变量的内容。您还可以回显任何 PHP 函数的结果。事实上,您可以将任何您希望的 PHP 代码放入 Blade echo 语句中:

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

HTML 实体编码

默认情况下,Blade(和 Laravele helper) 将对 HTML 实体进行双重编码。如果您想禁用双重编码,请调用Blade::withoutDoubleEncoding 方法来自boot 你的方法AppServiceProvider:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Blade::withoutDoubleEncoding();
    }
}

显示未转义的数据

默认情况下,刀片{{ }} 语句通过 PHP 自动发送htmlspecialchars 功能来防止XSS攻击。如果您不希望您的数据被转义,您可以使用以下语法:

Hello, {!! $name !!}.

Warning
回显应用程序用户提供的内容时要非常小心。在显示用户提供的数据时,您通常应该使用转义的双花括号语法来防止 XSS 攻击。

Blade 和 JavaScript 框架

由于许多 JavaScript 框架也使用“大括号”来指示给定的表达式应该在浏览器中显示,您可以使用@ 通知 Blade 渲染引擎一个表达式应该保持不变的符号。例如:

<h1>Laravel</h1>

Hello, @{{ name }}.

在这个例子中,@ 符号将被 Blade 删除;然而,{{ name }} 表达式不会被 Blade 引擎影响,允许它被你的 JavaScript 框架渲染。

@ 符号也可用于转义 Blade 指令:

{{-- Blade template --}}
@@if()

<!-- HTML output -->
@if()

呈现 JSON

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

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

但是,而不是手动调用json_encode, 你可以使用Illuminate\Support\Js::from 方法指令。这from 方法接受与 PHP 相同的参数json_encode 功能;但是,它将确保生成的 JSON 被正确转义以包含在 HTML 引号中。这from 方法将返回一个字符串JSON.parse 将给定对象或数组转换为有效 JavaScript 对象的 JavaScript 语句:

<script>
    var app = {{ Illuminate\Support\Js::from($array) }};
</script>

最新版本的 Laravel 应用程序框架包括一个Js facade,它在你的 Blade 模板中提供了对这个功能的方便访问:

<script>
    var app = {{ Js::from($array) }};
</script>

Warning
你应该只使用Js::from 将现有变量呈现为 JSON 的方法。 Blade 模板基于正则表达式,尝试将复杂的表达式传递给指令可能会导致意外失败。

@verbatim 指示

如果您在模板的大部分中显示 JavaScript 变量,您可以将 HTML 包装在@verbatim 指令,这样你就不必在每个 Blade echo 语句前加上@ 象征:

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

刀片指令

除了模板继承和显示数据外,Blade 还为常见的 PHP 控制结构(如条件语句和循环)提供了方便的快捷方式。这些快捷方式提供了一种非常干净、简洁的方式来处理 PHP 控制结构,同时也让 PHP 同行保持熟悉。

如果语句

你可以建造if 语句使用@if,@elseif,@else, 和@endif 指令。这些指令的功能与其对应的 PHP 指令相同:

@if (count($records) === 1)
    I have one record!
@elseif (count($records) > 1)
    I have multiple records!
@else
    I don't have any records!
@endif

为了方便起见,Blade 还提供了一个@unless 指示:

@unless (Auth::check())
    You are not signed in.
@endunless

除了已经讨论过的条件指令外,@isset@empty 指令可以用作各自 PHP 函数的便捷快捷方式:

@isset($records)
    // $records is defined and is not null...
@endisset

@empty($records)
    // $records is "empty"...
@endempty

身份验证指令

@auth@guest 指令可用于快速确定当前用户是否authenticated 或者是客人:

@auth
    // The user is authenticated...
@endauth

@guest
    // The user is not authenticated...
@endguest

如果需要,您可以指定在使用@auth@guest 指令:

@auth('admin')
    // The user is authenticated...
@endauth

@guest('admin')
    // The user is not authenticated...
@endguest

环境指令

您可以使用以下命令检查应用程序是否在生产环境中运行@production 指示:

@production
    // Production specific content...
@endproduction

或者,您可以使用@env 指示:

@env('staging')
    // The application is running in "staging"...
@endenv

@env(['staging', 'production'])
    // The application is running in "staging" or "production"...
@endenv

部分指令

您可以使用@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,@case,@break,@default@endswitch 指令:

@switch($i)
    @case(1)
        First case...
        @break

    @case(2)
        Second case...
        @break

    @default
        Default case...
@endswitch

Loops

除了条件语句之外,Blade 还提供了使用 PHP 循环结构的简单指令。同样,这些指令中的每一个都与其对应的 PHP 指令功能相同:

@for ($i = 0; $i < 10; $i++)
    The current value is {{ $i }}
@endfor

@foreach ($users as $user)
    <p>This is user {{ $user->id }}</p>
@endforeach

@forelse ($users as $user)
    <li>{{ $user->name }}</li>
@empty
    <p>No users</p>
@endforelse

@while (true)
    <p>I'm looping forever.</p>
@endwhile

Note
在遍历一个foreach 循环,你可以使用循环变量 以获得有关循环的有价值信息,例如您是在循环的第一次还是最后一次迭代中。

使用循环时,您还可以跳过当前迭代或使用@continue@break 指令:

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

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

    @if ($user->number == 5)
        @break
    @endif
@endforeach

您还可以在指令声明中包含继续或中断条件:

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

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

    @break($user->number == 5)
@endforeach

循环变量

在遍历一个foreach 循环,一个$loop 变量将在循环内可用。此变量提供对一些有用信息的访问,例如当前循环索引以及这是循环中的第一次还是最后一次迭代:

@foreach ($users as $user)
    @if ($loop->first)
        This is the first iteration.
    @endif

    @if ($loop->last)
        This is the last iteration.
    @endif

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

如果您处于嵌套循环中,则可以访问父循环的$loop 通过变量parent财产:

@foreach ($users as $user)
    @foreach ($user->posts as $post)
        @if ($loop->parent->first)
            This is the first iteration of the parent loop.
        @endif
    @endforeach
@endforeach

$loop 变量还包含各种其他有用的属性:

Property Description
$loop->index 当前循环迭代的索引(从 0 开始)。
$loop->iteration 当前循环迭代(从 1 开始)。
$loop->remaining 循环中剩余的迭代。
$loop->count 正在迭代的数组中的项目总数。
$loop->first 这是否是循环中的第一次迭代。
$loop->last 这是否是循环中的最后一次迭代。
$loop->even 这是否是循环中的偶数迭代。
$loop->odd 这是否是循环中的奇数迭代。
$loop->depth 当前循环的嵌套层级。
$loop->parent 在嵌套循环中时,父循环变量。

条件类和样式

@class 指令有条件地编译 CSS 类字符串。该指令接受一个类数组,其中数组键包含您要添加的一个或多个类,而值是一个布尔表达式。如果数组元素有数字键,它将始终包含在呈现的类列表中:

@php
    $isActive = false;
    $hasError = true;
@endphp

<span @class([
    'p-4',
    'font-bold' => $isActive,
    'text-gray-500' => ! $isActive,
    'bg-red' => $hasError,
])></span>

<span class="p-4 text-gray-500 bg-red"></span>

同样,@style 指令可用于有条件地将内联 CSS 样式添加到 HTML 元素:

@php
    $isActive = true;
@endphp

<span @style([
    'background-color: red',
    'font-weight: bold' => $isActive,
])></span>

<span style="background-color: red; font-weight: bold;"></span>

附加属性

为了方便起见,您可以使用@checked 指令轻松指示给定的 HTML 复选框输入是否已“选中”。该指令将回显checked 如果提供的条件评估为true:

<input type="checkbox"
        name="active"
        value="active"
        @checked(old('active', $user->active)) />

同样,@selected 指令可用于指示是否应“选择”给定的选择选项:

<select name="version">
    @foreach ($product->versions as $version)
        <option value="{{ $version }}" @selected(old('version') == $version)>
            {{ $version }}
        </option>
    @endforeach
</select>

此外,@disabled 指令可用于指示给定元素是否应“禁用”:

<button type="submit" @disabled($errors->isNotEmpty())>Submit</button>

此外,@readonly 指令可用于指示给定元素是否应为“只读”:

<input type="email"
        name="email"
        value="email@laravel.com"
        @readonly($user->isNotAdmin()) />

除此之外@required 指令可用于指示给定元素是否应该是“必需的”:

<input type="text"
        name="title"
        value="title"
        @required($user->isAdmin()) />

包括子视图

Note
在您免费使用@include 指令,刀片components 提供类似的功能,并提供比@include 指令,例如数据和属性绑定。

刀片的@include 指令允许您从另一个视图中包含一个 Blade 视图。对父视图可用的所有变量都将对包含的视图可用:

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

    <form>
        <!-- Form Contents -->
    </form>
</div>

即使被包含视图将继承父视图中可用的所有数据,您也可以传递一组应该对被包含视图可用的附加数据:

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

如果你试图@include 一个不存在的视图,Laravel 将抛出一个错误。如果你想包含一个可能存在也可能不存在的视图,你应该使用@includeIf 指示:

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

如果你愿意@include 如果给定的布尔表达式计算为true 或者false, 你可以使用@includeWhen@includeUnless 指令:

@includeWhen($boolean, 'view.name', ['status' => 'complete'])

@includeUnless($boolean, 'view.name', ['status' => 'complete'])

要包含给定视图数组中存在的第一个视图,您可以使用includeFirst 指示:

@includeFirst(['custom.admin', 'admin'], ['status' => 'complete'])

Warning
你应该避免使用__DIR____FILE__ Blade 视图中的常量,因为它们将引用缓存的编译视图的位置。

渲染集合视图

您可以将循环和包含与 Blade 组合成一行@each 指示:

@each('view.name', $jobs, 'job')

@each 指令的第一个参数是为数组或集合中的每个元素呈现的视图。第二个参数是您希望迭代的数组或集合,而第三个参数是将分配给视图中当前迭代的变量名称。因此,例如,如果您正在遍历一个数组jobs,通常您会希望将每个作业作为job 视图中的变量。当前迭代的数组键将作为key 视图中的变量。

您还可以将第四个参数传递给@each 指示。如果给定数组为空,此参数确定将呈现的视图。

@each('view.name', $jobs, 'job', 'view.empty')

Warning
通过呈现的视图@each 不要从父视图继承变量。如果子视图需要这些变量,你应该使用@foreach@include 指令代替。

@once 指示

@once 指令允许您定义模板的一部分,每个渲染周期只评估一次。这可能有助于将给定的 JavaScript 片段推送到页面的标题中stacks.例如,如果您正在渲染给定的component 在一个循环中,您可能希望只在第一次呈现组件时将 JavaScript 推送到标头:

@once
    @push('scripts')
        <script>
            // Your custom JavaScript...
        </script>
    @endpush
@endonce

自从@once 指令通常与@push 或者@prepend 指令,@pushOnce@prependOnce 为方便起见,可以使用指令:

@pushOnce('scripts')
    <script>
        // Your custom JavaScript...
    </script>
@endPushOnce

原始PHP

在某些情况下,将 PHP 代码嵌入到您的视图中很有用。你可以使用刀片@php 在模板中执行一段纯 PHP 的指令:

@php
    $counter = 1;
@endphp

如果您只需要编写一个 PHP 语句,则可以将该语句包含在@php 指示:

@php($counter = 1)

Comments

Blade 还允许您在视图中定义注释。但是,与 HTML 注释不同,Blade 注释不包含在您的应用程序返回的 HTML 中:

{{-- This comment will not be present in the rendered HTML --}}

Components

组件和插槽提供与部分、布局和包含类似的好处;然而,有些人可能会发现组件和插槽的心智模型更容易理解。有两种编写组件的方法:基于类的组件和匿名组件。

要创建基于类的组件,您可以使用make:component 工匠命令。为了说明如何使用组件,我们将创建一个简单的Alert 成分。这make:component 命令会将组件放在app/View/Components 目录:

php artisan make:component Alert

make:component 命令还将为组件创建一个视图模板。视图将放置在resources/views/components 目录。为您自己的应用程序编写组件时,会自动在app/View/Components 目录和resources/views/components 目录,因此通常不需要进一步的组件注册。

您还可以在子目录中创建组件:

php artisan make:component Forms/Input

上面的命令将创建一个Input 中的组件app/View/Components/Forms 目录和视图将被放置在resources/views/components/forms 目录。

如果你想创建一个匿名组件(一个只有 Blade 模板而没有类的组件),你可以使用--view 调用时标记make:component 命令:

php artisan make:component forms.input --view

上面的命令将在以下位置创建一个 Blade 文件resources/views/components/forms/input.blade.php 可以通过以下方式呈现为组件<x-forms.input />.

手动注册包组件

为您自己的应用程序编写组件时,会自动在app/View/Components 目录和resources/views/components 目录。

然而,如果你正在构建一个使用 Blade 组件的包,你将需要手动注册你的组件类和它的 HTML 标签别名。您通常应该在boot 您包裹的服务提供商的方法:

use Illuminate\Support\Facades\Blade;

/**
 * Bootstrap your package's services.
 */
public function boot(): void
{
    Blade::component('package-alert', Alert::class);
}

一旦你的组件被注册,它就可以使用它的标签别名来呈现:

<x-package-alert/>

或者,您可以使用componentNamespace 按照惯例自动加载组件类的方法。例如,一个Nightshade 包裹可能有CalendarColorPicker 驻留在Package\Views\Components 命名空间:

use Illuminate\Support\Facades\Blade;

/**
 * Bootstrap your package's services.
 */
public function boot(): void
{
    Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}

这将允许使用它们的供应商名称空间使用包组件package-name:: 句法:

<x-nightshade::calendar />
<x-nightshade::color-picker />

Blade 将通过组件名称的 pascal 大小写自动检测链接到该组件的类。使用“点”表示法也支持子目录。

渲染组件

要显示一个组件,您可以在您的一个 Blade 模板中使用一个 Blade 组件标签。 Blade 组件标签以字符串开头x- 后跟组件类的 kebab 大小写名称:

<x-alert/>

<x-user-profile/>

如果组件类嵌套在app/View/Components 目录,你可以使用. 指示目录嵌套的字符。例如,如果我们假设一个组件位于app/View/Components/Inputs/Button.php,我们可以这样渲染它:

<x-inputs.button/>

如果你想有条件地渲染你的组件,你可以定义一个shouldRender 组件类上的方法。如果shouldRender 方法返回false 该组件将不会被渲染:

use Illuminate\Support\Str;

/**
 * Whether the component should be rendered
 */
public function shouldRender(): bool
{
    return Str::length($this->message) > 0;
}

将数据传递给组件

您可以使用 HTML 属性将数据传递给 Blade 组件。可以使用简单的 HTML 属性字符串将硬编码的原始值传递给组件。 PHP 表达式和变量应该通过使用: 字符作为前缀:

<x-alert type="error" :message="$message"/>

您应该在其类构造函数中定义组件的所有数据属性。组件上的所有公共属性将自动提供给组件的视图。没有必要将数据从组件的视图传递到视图render 方法:

<?php

namespace App\View\Components;

use Illuminate\View\Component;
use Illuminate\View\View;

class Alert extends Component
{
    /**
     * Create the component instance.
     */
    public function __construct(
        public string $type,
        public string $message,
    ) {}

    /**
     * Get the view / contents that represent the component.
     */
    public function render(): View
    {
        return view('components.alert');
    }
}

呈现组件时,您可以通过按名称回显变量来显示组件公共变量的内容:

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

Casing

组件构造函数参数应使用指定camelCase, 尽管kebab-case 引用 HTML 属性中的参数名称时应使用。例如,给定以下组件构造函数:

/**
 * Create the component instance.
 */
public function __construct(
    public string $alertType,
) {}

$alertType 可以像这样向组件提供参数:

<x-alert alert-type="danger" />

短属性语法

将属性传递给组件时,您还可以使用“短属性”语法。这通常很方便,因为属性名称经常匹配它们对应的变量名称:

{{-- Short attribute syntax... --}}
<x-profile :$userId :$name />

{{-- Is equivalent to... --}}
<x-profile :user-id="$userId" :name="$name" />

转义属性渲染

由于某些 JavaScript 框架(例如 Alpine.js)也使用冒号前缀的属性,因此您可以使用双冒号 (::) 前缀来通知 Blade 该属性不是 PHP 表达式。例如,给定以下组件:

<x-button ::class="{ danger: isDeleting }">
    Submit
</x-button>

Blade 将呈现以下 HTML:

<button :class="{ danger: isDeleting }">
    Submit
</button>

组件方法

除了组件模板可用的公共变量外,还可以调用组件上的任何公共方法。例如,假设一个组件有一个isSelected 方法:

/**
 * Determine if the given option is the currently selected option.
 */
public function isSelected(string $option): bool
{
    return $option === $this->selected;
}

您可以通过调用与方法名称匹配的变量从组件模板中执行此方法:

<option {{ $isSelected($value) ? 'selected' : '' }} value="{{ $value }}">
    {{ $label }}
</option>

访问组件类中的属性和插槽

Blade 组件还允许您在类的渲染方法中访问组件名称、属性和插槽。但是,为了访问这些数据,您应该从组件的render 方法。关闭将收到一个$data 数组作为它唯一的参数。该数组将包含几个提供组件信息的元素:

use Closure;

/**
 * Get the view / contents that represent the component.
 */
public function render(): Closure
{
    return function (array $data) {
        // $data['componentName'];
        // $data['attributes'];
        // $data['slot'];

        return '<div>Components content</div>';
    };
}

componentName 等于 HTML 标记中使用的名称x- 字首。所以<x-alert />componentNamealert.这attributes 元素将包含 HTML 标记上存在的所有属性。这slot 元素是一个Illuminate\Support\HtmlString 包含组件插槽内容的实例。

闭包应该返回一个字符串。如果返回的字符串对应于现有视图,则将呈现该视图;否则,返回的字符串将被评估为内联 Blade 视图。

额外的依赖

如果你的组件需要 Laravel 的依赖项服务容器,你可以在任何组件的数据属性之前列出它们,它们将被容器自动注入:

use App\Services\AlertCreator;

/**
 * Create the component instance.
 */
public function __construct(
    public AlertCreator $creator,
    public string $type,
    public string $message,
) {}

隐藏属性/方法

如果你想阻止一些公共方法或属性作为变量暴露给你的组件模板,你可以将它们添加到$except 组件上的数组属性:

<?php

namespace App\View\Components;

use Illuminate\View\Component;

class Alert extends Component
{
    /**
     * The properties / methods that should not be exposed to the component template.
     *
     * @var array
     */
    protected $except = ['type'];

    /**
     * Create the component instance.
     */
    public function __construct(
        public string $type,
    ) {}
}

组件属性

我们已经研究了如何将数据属性传递给组件;然而,有时您可能需要指定额外的 HTML 属性,例如class,它们不是组件运行所需的数据的一部分。通常,您希望将这些附加属性向下传递到组件模板的根元素。例如,假设我们想要渲染一个alert 像这样的组件:

<x-alert type="error" :message="$message" class="mt-4"/>

所有不属于组件构造函数的属性都将自动添加到组件的“属性包”中。这个属性包通过$attributes 多变的。通过回显此变量,可以在组件内呈现所有属性:

<div {{ $attributes }}>
    <!-- Component content -->
</div>

Warning
使用指令,例如@env 目前不支持组件标签内。例如,<x-alert :live="@env('production')"/> 不会被编译。

默认/合并属性

有时您可能需要为属性指定默认值或将其他值合并到组件的某些属性中。为此,您可以使用属性包的merge 方法。此方法对于定义一组应始终应用于组件的默认 CSS 类特别有用:

<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
    {{ $message }}
</div>

如果我们假设这个组件是这样使用的:

<x-alert type="error" :message="$message" class="mb-4"/>

组件的最终渲染 HTML 将如下所示:

<div class="alert alert-error mb-4">
    <!-- Contents of the $message variable -->
</div>

有条件地合并类

有时您可能希望在给定条件满足时合并类true.您可以通过class 方法,它接受一个类数组,其中数组键包含您要添加的一个或多个类,而值是一个布尔表达式。如果数组元素有数字键,它将始终包含在呈现的类列表中:

<div {{ $attributes->class(['p-4', 'bg-red' => $hasError]) }}>
    {{ $message }}
</div>

如果您需要将其他属性合并到您的组件中,您可以链接merge 方法到class 方法:

<button {{ $attributes->class(['p-4'])->merge(['type' => 'button']) }}>
    {{ $slot }}
</button>

Note
如果您需要在不应接收合并属性的其他 HTML 元素上有条件地编译类,您可以使用@class 指示.

非类属性合并

合并不是的属性时class 属性,提供给的值merge 方法将被视为属性的“默认”值。然而,不同于class 属性,这些属性不会与注入的属性值合并。相反,它们将被覆盖。例如,一个button 组件的实现可能如下所示:

<button {{ $attributes->merge(['type' => 'button']) }}>
    {{ $slot }}
</button>

使用自定义渲染按钮组件type,它可以在使用组件时指定。如果没有指定类型,则button 类型将被使用:

<x-button type="submit">
    Submit
</x-button>

呈现的 HTMLbutton 此示例中的组件将是:

<button type="submit">
    Submit
</button>

如果您想要其他属性class 要将其默认值和注入值连接在一起,您可以使用prepends 方法。在这个例子中,data-controller 属性将始终以profile-controller 和任何额外注入data-controller 值将放置在此默认值之后:

<div {{ $attributes->merge(['data-controller' => $attributes->prepends('profile-controller')]) }}>
    {{ $slot }}
</div>

检索和过滤属性

您可以使用过滤属性filter 方法。这个方法接受一个应该返回的闭包true 如果你想保留属性包中的属性:

{{ $attributes->filter(fn (string $value, string $key) => $key == 'foo') }}

为了方便起见,您可以使用whereStartsWith 检索其键以给定字符串开头的所有属性的方法:

{{ $attributes->whereStartsWith('wire:model') }}

相反,whereDoesntStartWith 方法可用于排除其键以给定字符串开头的所有属性:

{{ $attributes->whereDoesntStartWith('wire:model') }}

使用first 方法,您可以渲染给定属性包中的第一个属性:

{{ $attributes->whereStartsWith('wire:model')->first() }}

如果您想检查组件上是否存在某个属性,您可以使用has 方法。此方法接受属性名称作为其唯一参数,并返回一个布尔值,指示该属性是否存在:

@if ($attributes->has('class'))
    <div>Class attribute is present</div>
@endif

您可以使用检索特定属性的值get 方法:

{{ $attributes->get('class') }}

保留关键字

默认情况下,一些关键字保留给 Blade 内部使用以渲染组件。以下关键字不能定义为组件中的公共属性或方法名称:

  • data
  • render
  • resolveView
  • shouldRender
  • view
  • withAttributes
  • withName

Slots

您通常需要通过“插槽”将其他内容传递给您的组件。组件插槽通过回显$slot 多变的。为了探索这个概念,让我们想象一个alert 组件具有以下标记:

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

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

我们可能会将内容传递给slot 通过将内容注入组件:

<x-alert>
    <strong>Whoops!</strong> Something went wrong!
</x-alert>

有时一个组件可能需要在组件内的不同位置呈现多个不同的插槽。让我们修改我们的警报组件以允许注入“标题”插槽:

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

<span class="alert-title">{{ $title }}</span>

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

您可以使用x-slot 标签。任何不在明确范围内的内容x-slot 标签将被传递到组件中$slot 多变的:

<x-alert>
    <x-slot:title>
        Server Error
    </x-slot>

    <strong>Whoops!</strong> Something went wrong!
</x-alert>

作用域插槽

如果您使用过 Vue 等 JavaScript 框架,您可能熟悉“作用域插槽”,它允许您从插槽内的组件访问数据或方法。你可以在 Laravel 中通过在组件上定义公共方法或属性并通过$component 多变的。在这个例子中,我们假设x-alert 组件有一个公共formatAlert 在其组件类上定义的方法:

<x-alert>
    <x-slot:title>
        {{ $component->formatAlert('Server Error') }}
    </x-slot>

    <strong>Whoops!</strong> Something went wrong!
</x-alert>

插槽属性

与 Blade 组件一样,您可以分配额外的attributes 到插槽,例如 CSS 类名:

<x-card class="shadow-sm">
    <x-slot:heading class="font-bold">
        Heading
    </x-slot>

    Content

    <x-slot:footer class="text-sm">
        Footer
    </x-slot>
</x-card>

要与插槽属性交互,您可以访问attributes 插槽变量的属性。有关如何与属性交互的更多信息,请参阅文档组件属性:

@props([
    'heading',
    'footer',
])

<div {{ $attributes->class(['border']) }}>
    <h1 {{ $heading->attributes->class(['text-lg']) }}>
        {{ $heading }}
    </h1>

    {{ $slot }}

    <footer {{ $footer->attributes->class(['text-gray-700']) }}>
        {{ $footer }}
    </footer>
</div>

内联组件视图

对于非常小的组件,同时管理组件类和组件的视图模板可能会感觉很麻烦。因此,您可以直接从render 方法:

/**
 * Get the view / contents that represent the component.
 */
public function render(): string
{
    return <<<'blade'
        <div class="alert alert-danger">
            {{ $slot }}
        </div>
    blade;
}

生成内联视图组件

要创建呈现内联视图的组件,您可以使用inline 执行时的选项make:component 命令:

php artisan make:component Alert --inline

动态组件

有时您可能需要渲染一个组件,但直到运行时才知道应该渲染哪个组件。在这种情况下,你可以使用 Laravel 的内置dynamic-componentcomponent 根据运行时值或变量呈现组件:

<x-dynamic-component :component="$componentName" class="mt-4" />

手动注册组件

Warning
以下关于手动注册组件的文档主要适用于编写包含视图组件的 Laravel 包的人员。如果您不是在编写程序包,那么组件文档的这一部分可能与您无关。

为您自己的应用程序编写组件时,会自动在app/View/Components 目录和resources/views/components 目录。

然而,如果你正在构建一个使用 Blade 组件的包或将组件放置在非常规目录中,你将需要手动注册你的组件类及其 HTML 标签别名,以便 Laravel 知道在哪里可以找到该组件。您通常应该在boot 您包裹的服务提供商的方法:

use Illuminate\Support\Facades\Blade;
use VendorPackage\View\Components\AlertComponent;

/**
 * Bootstrap your package's services.
 */
public function boot(): void
{
    Blade::component('package-alert', AlertComponent::class);
}

一旦你的组件被注册,它就可以使用它的标签别名来呈现:

<x-package-alert/>

自动加载包组件

或者,您可以使用componentNamespace 按照惯例自动加载组件类的方法。例如,一个Nightshade 包裹可能有CalendarColorPicker 驻留在Package\Views\Components 命名空间:

use Illuminate\Support\Facades\Blade;

/**
 * Bootstrap your package's services.
 */
public function boot(): void
{
    Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}

这将允许使用它们的供应商名称空间使用包组件package-name:: 句法:

<x-nightshade::calendar />
<x-nightshade::color-picker />

Blade 将通过组件名称的 pascal 大小写自动检测链接到该组件的类。使用“点”表示法也支持子目录。

匿名组件

与内联组件类似,匿名组件提供了一种通过单个文件管理组件的机制。但是,匿名组件使用单个视图文件并且没有关联的类。要定义一个匿名组件,你只需要在你的resources/views/components 目录。例如,假设您已经在resources/views/components/alert.blade.php,您可以像这样简单地渲染它:

<x-alert/>

您可以使用. 指示组件是否嵌套在更深的内部的字符components 目录。例如,假设组件定义在resources/views/components/inputs/button.blade.php,你可以这样渲染它:

<x-inputs.button/>

匿名索引组件

有时,当一个组件由许多 Blade 模板组成时,您可能希望将给定组件的模板分组到一个目录中。例如,想象一个具有以下目录结构的“手风琴”组件:

/resources/views/components/accordion.blade.php
/resources/views/components/accordion/item.blade.php

此目录结构允许您像这样呈现手风琴组件及其项目:

<x-accordion>
    <x-accordion.item>
        ...
    </x-accordion.item>
</x-accordion>

但是,为了通过x-accordion,我们被迫将“索引”手风琴组件模板放在resources/views/components 目录而不是将其嵌套在accordion 目录与其他手风琴相关的模板。

值得庆幸的是,Blade 允许你放置一个index.blade.php 组件模板目录中的文件。当一个index.blade.php 组件存在模板,它将被呈现为组件的“根”节点。因此,我们可以继续使用上面示例中给出的相同 Blade 语法;但是,我们将像这样调整我们的目录结构:

/resources/views/components/accordion/index.blade.php
/resources/views/components/accordion/item.blade.php

数据属性/属性

由于匿名组件没有任何关联的类,您可能想知道如何区分哪些数据应该作为变量传递给组件,哪些属性应该放在组件的属性包.

您可以使用@props 组件的 Blade 模板顶部的指令。组件上的所有其他属性都可以通过组件的属性包获得。如果你想给一个数据变量一个默认值,你可以指定变量名作为数组键,默认值作为数组值:

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

@props(['type' => 'info', 'message'])

<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
    {{ $message }}
</div>

鉴于上面的组件定义,我们可以像这样渲染组件:

<x-alert type="error" :message="$message" class="mb-4"/>

访问父数据

有时您可能希望在子组件内访问父组件的数据。在这些情况下,您可以使用@aware 指示。例如,假设我们正在构建一个由父级组成的复杂菜单组件<x-menu> 和孩子<x-menu.item>:

<x-menu color="purple">
    <x-menu.item>...</x-menu.item>
    <x-menu.item>...</x-menu.item>
</x-menu>

<x-menu> 组件可能有如下实现:

<!-- /resources/views/components/menu/index.blade.php -->

@props(['color' => 'gray'])

<ul {{ $attributes->merge(['class' => 'bg-'.$color.'-200']) }}>
    {{ $slot }}
</ul>

因为color prop 仅传递给父级(<x-menu>), 它不会在里面可用<x-menu.item>.但是,如果我们使用@aware 指令,我们可以让它在内部可用<x-menu.item> 还有:

<!-- /resources/views/components/menu/item.blade.php -->

@aware(['color' => 'gray'])

<li {{ $attributes->merge(['class' => 'text-'.$color.'-800']) }}>
    {{ $slot }}
</li>

Warning
@aware 指令无法访问未通过 HTML 属性显式传递给父组件的父数据。默认@props 未显式传递给父组件的值不能被@aware 指示。

匿名组件路径

如前所述,匿名组件通常是通过将 Blade 模板放置在您的resources/views/components 目录。然而,除了默认路径之外,你可能偶尔想要向 Laravel 注册其他匿名组件路径。

anonymousComponentPath 方法接受匿名组件位置的“路径”作为其第一个参数,并接受组件应放置在其下的可选“名称空间”作为其第二个参数。通常,应从boot 您的应用程序之一的方法服务供应商:

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Blade::anonymousComponentPath(__DIR__.'/../components');
}

如上例所示,当组件路径在没有指定前缀的情况下注册时,它们也可能在没有相应前缀的情况下在您的 Blade 组件中呈现。例如,如果一个panel.blade.php 组件存在于上面注册的路径中,它可能会被渲染成这样:

<x-panel />

前缀“命名空间”可以作为第二个参数提供给anonymousComponentPath 方法:

Blade::anonymousComponentPath(__DIR__.'/../components', 'dashboard');

当提供前缀时,该“命名空间”中的组件可以通过在呈现组件时将组件的命名空间作为组件名称的前缀来呈现:

<x-dashboard::panel />

建筑布局

使用组件的布局

大多数 Web 应用程序在不同的页面上保持相同的总体布局。如果我们必须在我们创建的每个视图中重复整个布局 HTML,那么维护我们的应用程序将非常麻烦和困难。值得庆幸的是,将此布局定义为单个布局很方便刀片组件 然后在我们的整个应用程序中使用它。

定义布局组件

例如,假设我们正在构建一个“todo”列表应用程序。我们可以定义一个layout 如下所示的组件:

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

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

应用布局组件

一旦layout 组件已经定义,我们可以创建一个使用该组件的 Blade 视图。在这个例子中,我们将定义一个简单的视图来显示我们的任务列表:

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

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

请记住,注入到组件中的内容将提供给默认$slot 我们内部的变量layout 成分。您可能已经注意到,我们的layout 也尊重一个$title 插槽(如果提供);否则,将显示默认标题。我们可以使用在组件文档:

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

<x-layout>
    <x-slot: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()]);
});

使用模板继承的布局

定义布局

布局也可以通过“模板继承”创建。这是在引入之前构建应用程序的主要方式components.

首先,让我们看一个简单的例子。首先,我们将检查页面布局。由于大多数 Web 应用程序在不同的页面上保持相同的总体布局,因此将此布局定义为单个 Blade 视图很方便:

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

<html>
    <head>
        <title>App Name - @yield('title')</title>
    </head>
    <body>
        @section('sidebar')
            This is the master sidebar.
        @show

        <div class="container">
            @yield('content')
        </div>
    </body>
</html>

如您所见,此文件包含典型的 HTML 标记。但是,请注意@section@yield 指令。这@section 顾名思义,指令定义了一段内容,而@yield 指令用于显示给定部分的内容。

现在我们已经为我们的应用程序定义了一个布局,让我们定义一个继承该布局的子页面。

扩展布局

定义子视图时,使用@extends 用于指定子视图应“继承”的布局的 Blade 指令。扩展 Blade 布局的视图可以使用@section 指令。请记住,如上例所示,这些部分的内容将显示在布局中使用@yield:

<!-- 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

在这个例子中,sidebar 部分正在利用@@parent 指令将内容附加(而不是覆盖)到布局的侧边栏。这@@parent 渲染视图时,指令将被布局的内容替换。

Note
与前面的例子相反,这个sidebar 部分以@endsection 代替@show.这@endsection 指令将只定义一个部分,而@show 将定义和立即屈服 这部分。

@yield 指令还接受一个默认值作为它的第二个参数。如果生成的部分未定义,则将呈现此值:

@yield('content', 'Default content')

Forms

CSRF 字段

任何时候在应用程序中定义 HTML 表单时,都应该在表单中包含一个隐藏的 CSRF 令牌字段,以便CSRF保护 中间件可以验证请求。您可以使用@csrf 用于生成令牌字段的 Blade 指令:

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

    ...
</form>

方法字段

由于 HTML 表单不能PUT,PATCH, 或者DELETE 请求,您将需要添加一个隐藏的_method 字段来欺骗这些 HTTP 动词。这@method Blade 指令可以为你创建这个字段:

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

    ...
</form>

验证错误

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

<!-- /resources/views/post/create.blade.php -->

<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 指令编译为“if”语句,您可以使用@else 当属性没有错误时渲染内容的指令:

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

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

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

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

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

<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

Stacks

Blade 允许您推送到命名堆栈,这些堆栈可以在另一个视图或布局中的其他地方呈现。这对于指定子视图所需的任何 JavaScript 库特别有用:

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

如果你愿意@push 给定布尔表达式计算结果为的内容true, 你可以使用@pushIf 指示:

@pushIf($shouldPush, 'scripts')
    <script src="/example.js"></script>
@endPushIf

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

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

    @stack('scripts')
</head>

如果您想将内容添加到堆栈的开头,您应该使用@prepend 指示:

@push('scripts')
    This will be second...
@endpush

// Later...

@prepend('scripts')
    This will be first...
@endprepend

服务注入

@inject 指令可用于从 Laravel 检索服务服务容器.第一个参数传递给@inject 是服务将被放入的变量的名称,而第二个参数是您希望解析的服务的类或接口名称:

@inject('metrics', 'App\Services\MetricsService')

<div>
    Monthly Revenue: {{ $metrics->monthlyRevenue() }}.
</div>

渲染内联刀片模板

有时您可能需要将原始的 Blade 模板字符串转换为有效的 HTML。您可以使用render 提供的方法Blade 正面。这render 方法接受 Blade 模板字符串和一个可选的数据数组以提供给模板:

use Illuminate\Support\Facades\Blade;

return Blade::render('Hello, {{ $name }}', ['name' => 'Julian Bashir']);

Laravel 通过将内联 Blade 模板写入到storage/framework/views 目录。如果你希望 Laravel 在渲染 Blade 模板后删除这些临时文件,你可以提供deleteCachedView 方法参数:

return Blade::render(
    'Hello, {{ $name }}',
    ['name' => 'Julian Bashir'],
    deleteCachedView: true
);

渲染刀片碎片

使用前端框架时,例如Turbohtmx,您可能偶尔需要在 HTTP 响应中只返回 Blade 模板的一部分。刀片“碎片”可以让您做到这一点。首先,将 Blade 模板的一部分放在@fragment@endfragment 指令:

@fragment('user-list')
    <ul>
        @foreach ($users as $user)
            <li>{{ $user->name }}</li>
        @endforeach
    </ul>
@endfragment

然后,在呈现使用此模板的视图时,您可以调用fragment 指定仅指定片段应包含在传出 HTTP 响应中的方法:

return view('dashboard', ['users' => $users])->fragment('user-list');

fragmentIf 方法允许您根据给定条件有条件地返回视图的片段。否则,将返回整个视图:

return view('dashboard', ['users' => $users])
    ->fragmentIf($request->hasHeader('HX-Request'), 'user-list');

fragmentsfragmentsIf 方法允许您在响应中返回多个视图片段。这些片段将连接在一起:

view('dashboard', ['users' => $users])
    ->fragments(['user-list', 'comment-list']);

view('dashboard', ['users' => $users])
    ->fragmentsIf(
        $request->hasHeader('HX-Request'),
        ['user-list', 'comment-list']
    );

加长刀片

Blade 允许你使用directive 方法。当 Blade 编译器遇到自定义指令时,它将使用指令包含的表达式调用提供的回调。

以下示例创建一个@datetime($var) 格式化给定的指令$var,这应该是一个实例DateTime:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        // ...
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Blade::directive('datetime', function (string $expression) {
            return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
        });
    }
}

如您所见,我们将链接format 方法传递给指令的任何表达式。因此,在此示例中,此指令生成的最终 PHP 将是:

<?php echo ($var)->format('m/d/Y H:i'); ?>

Warning
更新 Blade 指令的逻辑后,您需要删除所有缓存的 Blade 视图。可以使用删除缓存的 Blade 视图view:clear工匠命令。

自定义回声处理程序

如果您尝试使用 Blade 来“回显”一个对象,该对象的__toString 方法将被调用。这__toString method 是 PHP 内置的“魔法方法”之一。但是,有时您可能无法控制__toString 给定类的方法,例如当您与之交互的类属于第三方库时。

在这些情况下,Blade 允许您为该特定类型的对象注册自定义回显处理程序。为此,您应该调用 Blade 的stringable 方法。这stringable 方法接受一个闭包。这个闭包应该类型提示它负责呈现的对象的类型。通常,stringable 方法应该在boot 你的应用程序的方法AppServiceProvider 班级:

use Illuminate\Support\Facades\Blade;
use Money\Money;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Blade::stringable(function (Money $money) {
        return $money->formatTo('en_GB');
    });
}

一旦你的自定义回显处理程序被定义,你可以简单地回显你的 Blade 模板中的对象:

Cost: {{ $money }}

自定义 If 语句

在定义简单的自定义条件语句时,自定义指令的编程有时比必要的更复杂。为此,Blade 提供了一个Blade::if 允许您使用闭包快速定义自定义条件指令的方法。例如,让我们定义一个自定义条件来检查应用程序配置的默认“磁盘”。我们可以在boot 我们的方法AppServiceProvider:

use Illuminate\Support\Facades\Blade;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Blade::if('disk', function (string $value) {
        return config('filesystems.default') === $value;
    });
}

定义自定义条件后,您可以在模板中使用它:

@disk('local')
    <!-- The application is using the local disk... -->
@elsedisk('s3')
    <!-- The application is using the s3 disk... -->
@else
    <!-- The application is using some other disk... -->
@enddisk

@unlessdisk('local')
    <!-- The application is not using the local disk... -->
@enddisk
豫ICP备18041297号-2