Laravel Blade - @slot/@component与@include相比的优势是什么?

62

Laravel 5.4 Blade 引入了组件和插槽的概念 - 但我看不出它们相较于传统的 @include 带来了什么好处。据我理解,使用组件/插槽时,你需要:

在模板 component-tpl.blade.php 中:

<div class='container'>
  <h1>{{$slot1}}</h1>
  <h2>{{$slot2}}</h2>
</div>

使用页面模板中的插槽,您可以:

@component('component-tpl')
  @slot('slot1')
    The content of Slot 1
  @endslot
  @slot('slot2')
    The content of Slot 2
  @endslot
@endcomponent

那提供了哪些比旧版本更强大的功能:

@include('component-tpl',['slot1'=>'The content of Slot 1',
'slot2'=>"The content of Slot 2"])

使用完全相同的 'component-tpl.blade.php' Blade 模板,我漏掉了什么?感谢任何见解。

Chris


如果你正在开始一个新项目,那么@component看起来很不错。但是如果已经有一个使用了大量@include的现有项目,那么记住哪些部分是@component,哪些部分是@include似乎会很混乱。 - Cato Minor
5个回答

71

如先前所述,没有任何功能上的区别我是错误的-请参见benjaminhull的答案了解有关变量范围和传递Blade语法代码的详细信息。然而,以下内容仍适用于基本用法。

如果插槽可以包含HTML,则在您的Blade文件中使用组件将提供更清晰的语法。

@component('test')
   <strong>This text has html</strong>
@endcomponent

对抗

@include('test', ['slot' => '<strong>This text has HTML</strong>'])

同样,如果一个组件没有插槽,那么可能更喜欢使用include:

@include('test')

对决

@component('test')
@endcomponent

4
这段话的意思是:这个解释比简单地查阅文档更有用(因为文档通常不提供有用的用例)。我几周前才开始学习 Laravel 并且正在完成我的第一个项目。我搜索的原因正是你提供的例子。我有一些 HTML 代码,不想将它转换成字符串或者改动它,可以使用 ob_start(); ... return ob_get_clean() 这段代码。 - Phil Tune
这是一个很好的例子。我正在通过构建相互连接的刀片布局来简化一个复杂的应用程序,而这种区分真的帮助我区分部分和组件。 - DavidHyogo
1
有兴趣的人,请看一下DavidHyogo的回答。他提供了一个应该被考虑的优秀观点。 - Luís Henriques
“没有功能上的区别” - 这并不正确。请看我的和其他人的回答。恳请您更新您的回答,因为它是不正确的。 - benjaminhull

27

有两个关键的不同之处。

1. 变量作用域

如@DavidHyogo的回答中所述,组件只能看到明确传递给它的变量。因此你必须像这样传递所有变量...

@component('my-component', ['foo' => 'bar', 'etc' => 'etc'])

默认情况下,include语句会继承全局/当前作用域中的所有变量 - 除非您明确定义一组要传递给它的变量,这些变量将重新成为局部作用域。

{{-- This include will see all variables from the global/current scope --}}
@include('my-component')

{{-- This include will only see the variables explicitly passed in --}}
@include('my-component', ['foo' => 'bar', 'etc' => 'etc']) 

2. 组件的{{ $slot }}与include的{{ $var }}

在组件中使用{{ $slot }}, 你可以给它添加blade语法代码,例如...

{{-- alert.blade.php --}}
<div class="alert">{{ $slot }}</div>

@component('alert')
    <div>Hello {{ $name }} @include('welcome-message')</div>
@endcomponent

请注意,插槽将接收HTML和Blade语法代码并进行处理。
这是使用包含文件无法实现的,因为您只能将变量传递到包含文件中...
{{-- alert.blade.php --}}
<div class="alert">{{ $slot }}</div>

@include('alert', ['slot' => "I CAN'T PASS IN BLADE SYNTAX HERE!"])

可以通过一种更加hacky的方式来完成,即获取一个全新的view()助手并传递一些变量来编译我们想要传递到插槽中的输出,但这正是组件存在的原因。


24

我认为我已经找到了另一个关键的区别。例如,从5.4的文档中:

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

据我所知,组件与包含视图具有不同的作用域,因此父视图可用的变量在组件内不可用。您需要像这样向组件传递一个变量:

@component('alert', ['foo' => 'bar'])
@endcomponent

这个讨论与这个问题相关: 在Markdown邮件中使用变量


2
这很好,但仍有更多要考虑的因素。请查看我上面的回答。 - benjaminhull

7

正如文档所述:

组件和插槽提供类似于部分和布局的好处;然而,一些人可能会发现组件和插槽的思维模型更容易理解


7
我也阅读了文件,但那句话并没有帮助我区分这两个概念。我认为Rick的例子非常实用,有助于理解这两种方法的区别。 - DavidHyogo
这是关于“组件和插槽”与“部分和布局”的区别,而不是关于“包含”。 - PaulH

0

对于我来说,最重要的是组件需要一个。因此,当我只需要一个最简单的可重复使用的html(blade)部分时,无需创建blade文件+php文件,只需使用简单的@includesubview就足够了 ;)


3
组件不需要类,你可以只有一个 Blade 文件。它们也不需要一个 Blade 文件,可以只有一个类。 - Healyhatman
类似于内联组件,匿名组件提供了一种通过单个文件管理组件的机制。然而,匿名组件使用单个视图文件,并且没有关联的类。来源:https://laravel.com/docs/9.x/blade#anonymous-components - OLIVIERS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接