آشنایی با extends@ و yield@ در blade

extends and yield in blade

25 بهمن 1399
Laravel 7.0: آشنایی با extends@ و yield@ در blade (قسمت 08)

در قسمت قبل با برخی از متدهای کمکی لاراول در blade آشنا شدیم و حالا نوبت به نوشتن HTML و ظاهر اینستاگرام است. اگر یادتان باشد در جلسه قبل تصویر لوگوی روکسو را در فایل app.blade.php قرار دادیم:

لوگوی روکسو بیش از اندازه بزرگ شده است
لوگوی روکسو بیش از اندازه بزرگ شده است

همانطور که می بینید این شکل دو اشکال دارد: اولا لوگو بیش از حد بزرگ است و دوما لوگو و نوشته ما روی هم قرار گرفته اند. مشکل اول را با یک تگ استایل و height ساده حل می کنم:

<div><img src="/img/roxo-logo.png" alt="Roxo Logo" style="height: 25px"></div>

و برای مشکل دوم از بوت استرپ استفاده کرده و کلاس d-flex را به آن می دهیم:

<a class="navbar-brand d-flex" href="{{ url('/') }}">
    <div><img src="/img/roxo-logo.png" alt="Roxo Logo" style="max-height: 25px"></div>
    <div>RoxoGram</div>
</a>

در حال حاضر لوگوی روکسو در کنار نوشته RoxoGram قرار می گیرد اما به هم چسبیده اند و باید آن ها را از هم جدا کنیم بنابراین:

<a class="navbar-brand d-flex" href="{{ url('/') }}">
    <div><img src="/img/roxo-logo.png" alt="Roxo Logo" class="pr-3" style="height: 25px">
    </div>
    <div class="pl-3">RoxoGram</div>
</a>

من به هر کدام کلاس های pr (همان padding-right - ما از بوت استرپ استفاده می کنیم) و pl (مخفف padding left) را داده ام تا از هم فاصله پیدا کنند. من می خواهم بین آن ها خطی را نیز قرار بدهم بنابراین به تصویر لوگو یک border-right می دهم:

<a class="navbar-brand d-flex" href="{{ url('/') }}">
    <div><img src="/img/roxo-logo.png" alt="Roxo Logo" class="pr-3"
            style="height: 25px; border-right: 1px solid #333; vertical-align: text-bottom">
    </div>
    <div class="pl-3">RoxoGram</div>
</a>

من علاوه بر اضافه کردن border-right از vertical-align هم استفاده کرده ام تا لوگوی روکسو با نوشته RoxoGram در یک سطح قرار بگیرند:

لوگوی روکسو باید با نوشته ی کنار آن همسطح و همتراز باشد
لوگوی روکسو باید با نوشته کنار آن همسطح و همتراز باشد

این می شود header برنامه ما. حالا به فایل home.blade.php در پوشه views می رویم کدهای درون section را حذف می کنیم تا محتویات آن به شکل زیر در بیاید:

@extends('layouts.app')

@section('content')
<div class="container">

</div>
@endsection

همانطور که می بینید در این قسمت extends@ و section@ را داریم که از ویژگی های blade هستند بنابراین باید آن ها را برایتان توضیح بدهم. بیایید دوباره به فایل app.blade.php برگردیم. اگر دقت کنید در انتهای این فایل قسمتی به شکل زیر را پیدا می کنید:

<main class="py-4">
    @yield('content')
</main>

فایل app.blade.php یک layout است یعنی یک قالب کلی است که ساختار کلی صفحات سایت ما را دارد تا مجبور نشویم قسمت های تکراری را چندین بار در فایل های HTML مختلف بنویسیم. به این فایل یک view پدر می گوییم. حالا در کد بالا دستور yield@ را داریم که کارش دریافت یک قسمت تعریف شده است. در اینجا yield@ ما به دنبال قسمتی به نام content است تا آن را در اینجا نمایش بدهد. به نظر شما این قسمت کجاست؟ به فایل home.blade.php بروید و دوباره به کد زیر نگاه کنید:

@extends('layouts.app')

@section('content')
<div class="container">

</div>
@endsection

در این فایل اول از همه دستور extends@ را داریم که مشخص می کند این view فرزند باید از چه view پدری ارث بری داشته باشد. یعنی ساختار کلی این view چطور است؟ ما گفته ایم layouts.app که یعنی در پوشه layouts به دنبال فایل app.blade.php بگرد و از آن به عنوان قالب کلی استفاده کن (در blade با نقطه آدرس دهی می کنیم، شروع آدرس دهی از پوشه views است و پسوند blade.php را نیز نمی آوریم). تا این مرحله فایل های app.blade.php و home.blade.php را به هم متصل کرده ایم و رابطه بین آن ها را تعریف کرده ایم:

  • فایل blade.php فایل پدر است و ساختار کلی را مشخص می کند.
  • فایل blade.php فایل فرزند است و ساختار کلی پدر را به ارث می برد. هر جایی که extends@ دیدیم، آن فایل یک فایل فرزند یا view فرزند است.

حالا که دو فایل به هم متصل شده اند دستور section@ را داریم که مسئول تعریف یک section (به معنی «قسمت») می باشد. آرگومان پاس داده شده به این دستور یک نام دلخواه است که اینجا content در نظر گرفته شده است اما شما می توانید آن را تغییر دهید. تمام محتویاتی که بین section@ و endsection@ می نویسید در قالب یک «قسمت» با نام پاس داده شده تعریف می شوند. حالا باید در جایی تزریق شوند. کجا؟ قسمت yield@ در فایل پدر، یعنی app.blade.php! با این کار جلوی نوشتن کدهای تکراری (مثل header که در تمام صفحات تکراری است) را گرفته ایم. یادتان باشد که نام تعیین شده برای section@ در اینجا باید با نام داده شده به yield@ یکی باشد تا بتواند آن را پیدا کند.

سوال: اگر در قسمت yield@ در فایل پدر کدهایی داشته باشیم و نخواهیم که قسمت section در فایل فرزند، کل این کدها را حذف کند چطور؟ اگر بخواهیم کدهای section به yield پیوست شوند چطور؟

پاسخ: رفتار پیش فرض لاراول این است که قسمت yield@ را کاملا حذف کرده و قسمت section@ را از فرزند گرفته و درون yield@ می گذارد (عملیات override) اما اگر از دستور parent@ استفاده کنید، به جای override از عملیات append (پیوست) استفاده خواهد شد و به کدهای درون yield@ دست نمی خورد. بگذارید برایتان مثالی بزنیم.

تصور کنید که در فایل پدر (مثلا 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>

در ابتدا یک yield@ داریم که برای دریافت نام برنامه است. سپس یک section@ را داریم که قسمتی به نام sidebar را تعریف می کند (نام دلخواه است چرا که در حال تعریف یک قسمت هستیم) اما با دستور show@ تمام می شود نه با دستور endsection@ که بعدا در این مورد توضیح می دهم. سپس دوباره یک yield@ را داریم که به دنبال قسمتی به نام Content می گردد (نام اینجا دلخواه نیست چرا که در حال تعریف نیستیم، بلکه به دنبال این نام می گردیم).

حالا تصور کنید که در فایل فرزند این کد را داریم:

@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

اول با استفاده از extends@ گفته ایم که فایل پدر کجاست تا رابطه برقرار شود. سپس section ای به نام title تعریف کرده ایم (در فایل پدر به دنبال این title بودیم) و مقدار آن را یک رشته ساده برابر Page Title گذاشته ایم. بنابراین page title از اینجا در فایل پدر تزریق می شود و تگ زیر را می سازد:

<title>App Name - Page Title</title>

سپس section دیگری به نام sidebar را تعریف کرده ام که parent@ را در آن صدا می زنیم. با این کار به لاراول گفته ایم که محتوای موجود در فایل پدر را حذف نکند. در sidebar در فایل پدر یک رشته بدین شکل داشتیم:

This is the master sidebar.

با صدا زدن parent@ دیگر این رشته حذف نمی شود. در نهایت هم content را به عنوان یک section دیگر تعریف کرده ایم.

نکته: دستور endsection@ فقط پایان یک section را مشخص می کند اما show@ علاوه بر این کار عملیات yield@ را نیز انجام می دهد.

امیدوارم درک بهتری نسبت به blade پیدا کرده باشید.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری ساخت اینستاگرام با Laravel 7 توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما (1 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

علیرضا
22 مهر 1401
سلام، حواستون پرت شده و این بخش رو اشتباه نوشتید. فایل blade.php فایل پدر است و ساختار کلی را مشخص می کند. فایل blade.php فایل فرزند است و ساختار کلی پدر را به ارث می برد. هر جایی که extends@ دیدیم، آن فایل یک فایل فرزند یا view فرزند است. در هر دو نوشتید فایل blade.php

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.