اگر پیشتر با فناوریهای مرتبط با خانوادهی ASP.NET کار کرده باشید، با مفاهیمی مانند ContentPlaceHolder در وبفرمها و یا
RenderSection در ASP.NET MVC، برخورد داشتهاید. دقیقا یک چنین قابلیتی نیز به Blazor 8x تحت عنوان Sections اضافه شدهاست تا توسط آن بتوان محتوای قسمتی از قالب کلی صفحه را از طریق زیر کامپوننتهای آن تغییر داد و کنترل کرد.
کامپوننتهای جدید SectionOutlet و SectionContent در Blazor 8x
پیاده سازی Sections در Blazor 8x به کمک دو کامپوننت جدید SectionOutlet و SectionContent میسر شدهاست و برای دسترسی به آنها نیاز است ابتدا به فایل Imports.razor_ پروژه، مراجعه کرد و using زیر را به آن اضافه نمود تا این اشیاء، در کامپوننتهای برنامه قابل شناسایی و استفاده شوند:
@using Microsoft.AspNetCore.Components.Sections
SectionOutlet کامپوننتی است که محتوای ارائه شدهی توسط کامپوننت SectionContent را رندر میکند (این محتوا در اصل یک RenderFragment است). ارتباط بین این دو هم توسط خواص SectionName و یا SectionIdهای متناظر، برقرار میشود. اگر چندین SectionContent دارای نام و یا Id یکسانی باشند، محتوای آخرین آنها در SectionOutlet متناظر، رندر میشود.
برای مثال در فایل MainLayout.razor، تغییر زیر را اعمال میکنیم:
<div class="top-row px-4">
<SectionOutlet SectionName="before-top-row"/>
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
</div>
که در آن یک SectionOutlet، با نام before-top-row اضافه شدهاست و سبب درج محتوایی پیش از لینک About میشود. پس از این تعریف، اکنون در هر کامپوننتی از برنامه میتوان محتوای این قسمت را به نحو زیر تامین کرد:
<SectionContent SectionName="before-top-row">
<a href="/show-help" target="_blank">Help</a>
</SectionContent>
همانطور که مشخص است، این محتوا بر اساس نام ذکر شدهی متناظر با نام SectionOutlet، با آن ارتباط برقرار میکند.
روش تعریف یک محتوای پیشفرض
این محتوا، فقط زمانی تامین خواهد شد که کامپوننت در حال نمایش SectionContent، قابل مشاهده و فعال شده باشد. یعنی اگر از کامپوننت نمایش دهندهی آن به صفحهی دیگری رجوع کنیم، محتوای SectionOutlet مجددا خالی خواهد شد، تا زمانیکه به آدرس نمایش دهندهی کامپوننت دربرگیرندهی SectionContent متناظر با آن رجوع کنیم. به همین جهت اگر علاقمند به نمایش یک «محتوای پیشفرض» هستید، میتوان به صورت زیر عمل کرد:
<div class="top-row px-4">
<SectionOutlet SectionName="before-top-row" />
<SectionContent SectionName="before-top-row">
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
</SectionContent>
</div>
به این ترتیب حتی اگر در لحظهی نمایش کامپوننت جاری، هیچ SectionContent متناظری یافت نشد، از همان SectionContent ذیل این SectionOutlet، برای تامین محتوای آن استفاده میشود و اگر کامپوننتی محتوای جدیدی را تعریف کرد، چون همیشه آخرین SectionContent رندر شده، محتوای نهایی را تامین میکند، این محتوای جدید، جایگزین نمونهی پیشفرض خواهد شد.
تفاوت SectionId با SectionName
کامپوننت SectionOutlet، هم میتواند یک SectionName را دریافت کند و هم یک SectionId را. SectionNameها، رشتهای هستند و تغییرات آتی آنها تحت نظارت کامپایلر نیست. به همین جهت اگر نیاز به Refactoring آنها است، شاید بهتر باشد از خاصیت SectionId که یک Id از نوع strongly typed را مشخص میکند، استفاده کنیم.
برای نمونه میتوان مثال قبلی را به صورت زیر با استفاده از یک SectionId، بازنویسی کرد:
<div class="top-row px-4">
<SectionOutlet SectionId="BeforeTopRow" />
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
</div>
@code{
public static SectionOutlet BeforeTopRow = new();
}
که در اینجا SectionId، یک فیلد استاتیک از نوع SectionOutlet است.
سپس هر کامپوننت دیگری که بخواهد از این Id استاتیک استفاده کند، روش کار آن به صورت زیر است:
<SectionContent SectionId="MainLayout.BeforeTopRow">
<a href="/show-help" target="_blank">Help</a>
</SectionContent>