1. 定义布局

Blade 的两个主要优点是 **模板继承****区块**。为方便入门,让我们先通过一个简单的例子来上手。首先,我们来研究一个「主」页面布局。因为大多数 web 应用会在不同的页面中使用相同的布局方式,因此可以很方便地定义单个 Blade 布局视图:
@section : 定义了模板的内容
@yield : 显示指定的内容

  1. <!-- 位于 resources/views/layouts/app.blade.php -->
  2. <html>
  3. <head>
  4. <title>App Name - @yield('title')</title>
  5. </head>
  6. <body>
  7. @section('sidebar')
  8. This is the master sidebar.
  9. @show
  10. <div class="container">
  11. @yield('content')
  12. </div>
  13. </body>
  14. </html>

父页面显示的效果:
image.png

这里网页title只显示了 App Name - 说明了@yield()定义的内容不会显示出来,如果我稍作修改,给yield额外添加一个参数,第二个参数作为一个默认值会在 [yield] 片段未定义时被渲染出来

  1. <title>App Name - @yield('title', 'fa')</title>

效果如下:
image.png

这是fa网页的渲染后的源码,@yield看起来像是一个占位符,它什么也没有做。

  1. <!-- 位于 resources/views/layouts/app.blade.php -->
  2. <html>
  3. <head>
  4. <title>App Name - fa</title>
  5. </head>
  6. <body>
  7. This is the master sidebar.
  8. <div class="container"></div>
  9. </body>
  10. </html>

2. 继承布局

在定义一个子视图时,使用 Blade 的 @extends 指令指定子视图要「继承」的视图。扩展自 Blade 布局的视图可以使用 @section 指令向布局片段注入内容。就如前面的示例中所示,这些片段的内容将由布局中的 @yield 指令控制显示:

  1. <!-- 位于 resources/views/layouts/child.blade.php -->
  2. @extends('layouts.app')
  3. @section('title', 'Page Title')
  4. @section('sidebar')
  5. @parent
  6. <p>This is appended to the master sidebar.</p>
  7. @endsection
  8. @section('content')
  9. <p>This is my body content.</p>
  10. @endsection

页面效果
image.png

我们通过观察可以发现 :
@extends指令是继承
@section(‘title’, ‘Page Title’) 修改了页面的标题使用了第二个参数作为默认值。
@parent 指令好像是追加内容


3. 测试

我发现通过官方手册你根本就不可能知道这些指令的作用,而且区别也分不清,脾气来了自己整理一下。参考:https://www.kancloud.cn/baidu/laravel5/30671

3.1 思考1:

  • @yield@section 都是用来预定义可替代区块,二者的区别是什么?

@yield 定义的内容是不可以扩展的,子模板无法继承。@section既可以被替代,也可以被扩展。光这么说真的相当于没说,上代码。

demo1

先定义一个父模板

  1. {{-- father --}}
  2. {{-- 1.第一个参数只是定义一个区块的名称,作用和 @section类似 2.第二个参数是默认值,如果定义了就会显示 --}}
  3. @section('title')
  4. 我是父页面定义的title <br>
  5. @endsection
  6. @yield('title','我是父页面的默认标题')
  7. @section('content')
  8. 我是父页面的默认内容 <br>
  9. @show

postman 访问
image.png

分析:lin5~line7 我们在父页面定义了 title 这个区块,如果将line7 的 @endsection 换成 @show name就会多出一行显示的内容 我是父页面定义的title,从字面意思上看,猜都可以猜出 @show是用来显示定义的区块内容的。由于我先定义了 title这个区块所以呢,下面的@yield是不会显示出默认内容的,再往下面页面会显示我定义的 ‘content’ ,如果@yield就是这样用在父页面,那也太没意思了。

demo2

定义一个子模板,继承上面的模板

  1. {{-- child --}}
  2. @extends('test.father')
  3. @section('title')
  4. @parent
  5. 我是子页面追加的title
  6. @stop
  7. @section('content')
  8. @parent
  9. 我是子页面扩展的内容
  10. @stop

postman 访问
image.png

demo3

这样看感觉也并不是很清楚,我们可以一步一步分析。现在我改变这个子模板文件,我就让它去继承父模板,然后什么也不干。代码入下:

  1. {{-- child --}}
  2. @extends('test.father')
  3. {{--@section('title')--}}
  4. {{-- @parent--}}
  5. {{-- 我是子页面追加的title--}}
  6. {{--@stop--}}
  7. {{--@section('content')--}}
  8. {{-- @parent--}}
  9. {{-- 我是子页面扩展的内容--}}
  10. {{--@stop--}}

postman 访问
image.png

分析:这里仅仅显示了两行内容,答案很明显了。继承后显示的是下面我打上√的部分,也就是说我们在父页面使用 @section 定义的区块,默认情况下通过继承子页面也是会显示到这些区块的,而@yield这个就不会。所以@yield不可被继承,没有扩展性,而@section是具有扩展性的,默认就是被子模板继承。

  1. @section('title')
  2. 我是父页面定义的title <br>
  3. @endsection
  4. @yield('title','我是父页面的默认标题') ×
  5. @section('content')
  6. 我是父页面的默认内容 <br>
  7. @show

继续思考demo2的结果。我先给每一句编个号,然后分析一波,demo2 中的代码 执行到 line4 @section('title') ... ... 发现了可以从父页面继承这个title区块,于是编号1的结果就被打印了,然后在去解析的时候又发现 line5 **@parent** line6 我是子页面追加的title 所以编号2的结果被追加打印了出来,由于没有换行符号,所以呢。解析子页面 line9 的代码时就接着在这一行显示喽,后面的继续先显示了继承自父页面的内容,然后追加了子页面自身的内容。

  1. 1.我是父页面定义的title
  2. 2.我是子页面追加的title 3.我是父页面的默认内容
  3. 4.我是子页面扩展的内容

3.2 思考2:

@show 与 @stop

其实@section的结束关键字在早期有这个@endsection ,不过在4.0的版本就已经被移除并且不建议使用了,虽然它是向下兼容的。
@show 指的是执行到此处将 section 的内容输出到页面中,也就是显示。@stop 是只进行内容解析并且对这个 section 停止处理,除非使用 @override 来进行覆盖。通常来说,在首次定义某个 section 的时候,应该用 @show,而在替换它或者扩展它的时候,不应该用 @show,应该用 @stop

父页面

  1. {{-- test.father2 --}}
  2. <div id="zoneA">
  3. @section('zoneA')
  4. AAA
  5. @show
  6. </div>
  7. <div id="zoneB">
  8. @section('zoneB')
  9. BBB
  10. @stop
  11. </div>
  12. <div id="zoneC">
  13. @section('zoneC')
  14. CCC
  15. @show
  16. </div>

父页面显示情况
image.png

分析父页面:父页面的显示情况没啥说的,@show显示section定义的内容,@stop就不会显示喽。

子页面

  1. {{-- test.child2 --}}
  2. @extends('test.father2')
  3. @section('zoneA')
  4. aaa
  5. @stop
  6. @section('zoneB')
  7. bbb
  8. @stop
  9. @section('zoneC')
  10. ccc
  11. @show

子页面显示情况
image.png

分析子页面:如果我注释子页面其他的内容,只是继承于父页面,代码如下

  1. {{-- test.child2 --}}
  2. @extends('test.father2')

显示的效果
image.png

网页的源码

  1. <div id="zoneA">
  2. AAA
  3. </div>
  4. <div id="zoneB">
  5. </div>
  6. <div id="zoneC">
  7. CCC
  8. </div>

zoneB 的内容丢失,因为没有用 @show 告诉引擎输出这部分的内容,而 zoneC 的内容会显示两次,并且还破坏了 因为 @show 出现了两次。如果想要在子页面追加内容就一定要使用@partent指令,否则只是使用了@stop就像是完全重写了父类的方法一样。使用@show 就一定会显示出来,所以。子模板如果继承父模板就使用@stop好了,如果想要追加内容,就在里面添加@parent就好了。还是前面的那句话替换和扩展父模板使用@stop,放弃@show


@append 和 @override

通过上一个例子我们分析出@stop 是在子模板中指明内容替换父模板的默认内容。它好像做了重写的事情,那么@override 干啥捏。这里涉及到了一个这样的问题:section在模板中是可以多次使用的问题,代码照搬。

父模板

  1. {{-- father3 --}}
  2. <div>
  3. @yield('content')
  4. </div>

访问父模板,页面什么都不会显示
image.png

子模板

  1. {{-- child3 --}}
  2. @extends('test.father3')
  3. @section('content')
  4. 加一行内容<br>
  5. @append
  6. @section('content')
  7. 再加一行内容<br>
  8. @append
  9. @section('content')
  10. 加够了,到此为止吧。<br>
  11. @stop

访问子模板
image.png

父模板没有显示这是意料之中的事情,子模板只是显示了两句话,网上的这个例子会将三句话都显示出来,应该是Larvel版本的问题,**@append** 就有扩展的意思,从此处接着扩展内容。

如果我改写一下代码,如下所示:这里我看例子上的 override无效换成了overwrite

  1. {{-- child3 --}}
  2. @section('content')
  3. 加一行内容
  4. @append
  5. @section('content')
  6. 再加一行内容
  7. @append
  8. @section('content')
  9. 加够了,结束吧
  10. @stop
  11. @section('content')
  12. 都不要了,我说的。
  13. @overwrite

效果:什么也没有,可能还是Larvel版本的问题呢
image.png