-->

Laravel Blade - Chain/Embed multiple layouts

2020-07-03 03:30发布

问题:

In my favorite templating frameworks they typically have the ability to nest layouts. Is this something that is possible in Blade?

For example...

master.blade.php

<html>
  <head><!-- stuff --></head>
  <body>
    @yield('content')
  </body>
</html>

nav.blade.php

@extend('master')
<nav>
    <!-- nav content -->
</nav>
@yeild('content')

breadcrumb.blade.php

@extend('nav')
<breadcrumb>
    <!-- breadcrumb content -->
</breadcrumb>
@yield('content')

home.blade.php

@extend('nav')
@section('content')
    <home>
        <!-- content -->
    </home>
@endsection

about.blade.php

@extend('breadcrumb')
@section('content')
    <about>
        <!-- content -->
    </about>
@endsection

The reason I love this format is that it makes it extremely elegant (IMO) to be able to choose your injection point!

  • Have a one off landing page...reference master
  • For the homepage...reference nav
  • For any subpages (about/nav/product) reference breadcrumb

The layouts cascade and 'content' gets rebuilt with the compiled html as it goes up the tree.

Is this possible? I'm hoping to avoid doing @include in the layouts as I personally find them cumbersome and a bit of an eye sore especially when you get to elements that are repeated often, but not everywhere (breadcrumbs).

EDIT: Based on answers.

Ideally 'content' would be rebuilt and passed up the chain of nested layouts. i.e. If you have the homepage which references nav.blade.php the homepage content gets added to the nav layout and compiled. Then since the nav layout references master.blade.php the compiled layout would be passed up to master and built again. No duplicating of any content.

回答1:

You forgot using @parent. Here's the example:


master.blade.php

<html>
  <head>
    {{-- Stuff --}}
  </head>
  <body>
    @yield('content')
  </body>
</html>

nav.blade.php

You need to put the nav inside section to tell master layout that this is a content. If you don't, nav will be in the top of master layout (yes, outside html).

@extends('master')

@section('content')
  <nav>
    <p>nav content</p>
  </nav>
@endsection

home.blade.php

In this example, the content section is utilizing the @parent directive to append (rather than overwriting) content to the layout's sidebar. The @parent directive will be replaced by the content of the layout when the view is rendered.

@extends('nav')

@section('content')
  {{-- You can control where @parent should be rendered --}}
  @parent

  <home>
    <p>home content</p>
  </home>

  {{-- You can put your @parent here, give it a try --}}
@endsection

breadcrumb.blade.php

@extends('nav')

@section('content')
  {{-- You can control where @parent should be rendered --}}
  @parent

  <breadcrumb>
    <p>breadcrumb content</p>
  </breadcrumb>

  {{-- You can put your @parent here, give it a try --}}
@endsection

about.blade.php

@extends('breadcrumb')

@section('content')
  {{-- You can control where @parent should be rendered --}}
  @parent

  <about>
    <p>about content</p>
  </about>

  {{-- You can put your @parent here, give it a try --}}
@endsection

Rendered:

home.blade.php

<html>
<head>
</head>
<body>
  <nav>
    <p>nav content</p>
  </nav>
  <home>
    <p>home content</p>
  </home>
</body>
</html>

about.blade.php

<html>
<head>
</head>
<body>
  <nav>
    <p>nav content</p>
  </nav>
  <breadcrumb>
    <p>breadcrumb content</p>
  </breadcrumb>
  <about>
    <p>about content</p>
  </about>
</body>
</html>


回答2:

I'm not sure I get what you're after here. For instance in home.blade.php you extend "nav", which in turn extends "master", but both "master" and "nav" yield content, so the <home> content will render twice.

So, what is your expected output? I'm not sure "home" or "about" should really extend "nav" or "breadcrumb". I think of these two as sort of structural layout components, so it does make sense to me to include them in the master layout. In "nav" you can define a section to extend when your view needs a breadcrumb.

For instance:

master.blade.php

<html>
<head><!-- stuff --></head>
  <body>
    @include('nav')        
    @yield('content')
  </body>
</html>

nav.blade.php

<nav>
  <!-- nav content -->
  @yield('breadcrumb')
</nav>

home.blade.php

@extend('master')

@section('content')
  <home>
    <!-- content -->
  </home>
@endsection

about.blade.php

@extend('master')

@section('breadcrumb')
  <breadcrumb>
    <!-- breadcrumb content -->
  </breadcrumb>
@endsection

@section('content')
  <about>
    <!-- content -->
  </about>
@endsection