تا اینجا با نحوهی تعریف کامپوننتها و انتقال اطلاعات به آنها و برعکس، آشنا شدیم. در ادامه علاقمندیم اگر کامپوننتی را به صورت زیر تعریف کردیم:
<Comp1>This is a content coming from the parent</Comp1>
محتوایی را که بین تگهای این کامپوننت فرزند، توسط کامپوننت والد تنظیم شدهاست، در قسمت مشخصی از UI کامپوننت فرزند نمایش دهیم.
معرفی مفهوم Render Fragment
برای درج محتوای تامین شدهی توسط کامپوننت والد در یک کامپوننت فرزند، از ویژگی به نام Render Fragment استفاده میشود. مثالی جهت توضیح جزئیات آن:
در ابتدا یک کامپوننت والد جدید را در مسیر Pages\LearnBlazor\ParentComponent.razor به صورت زیر تعریف میکنیم:
@page "/ParentComponent"
<h1 class="text-danger">Parent Child Component</h1>
<ChildComponent Title="This title is passed as a parameter from the Parent Component">
A `Render Fragment` from the parent!
</ChildComponent>
<ChildComponent Title="This is the second child component"></ChildComponent>
@code {
}
- در اینجا یک کامپوننت متداول با مسیریابی منتهی به ParentComponent/ تعریف شدهاست.
- سپس دوبار کامپوننت فرضی ChildComponent به همراه پارامتر Title و یک محتوای جدید قرار گرفتهی در بین تگهای آن، در صفحه تعریف شدهاند.
- بار دومی که ChildComponent در صفحه قرار گرفتهاست، به همراه محتوای جدیدی در بین تگهای خود نیست.
برای دسترسی به این کامپوننت از طریق منوی برنامه، مدخل منوی آنرا به کامپوننت Shared\NavMenu.razor اضافه میکنیم:
<li class="nav-item px-3">
<NavLink class="nav-link" href="ParentComponent">
<span class="oi oi-list-rich" aria-hidden="true"></span> Parent/Child Relation
</NavLink>
</li>
اکنون میخواهیم کامپوننت ChildComponent را افزوده و انتظارت یاد شده (دریافت یک پارامتر و نمایش محتوای سفارشی تنظیم شده) را پیاده سازی کنیم. به همین جهت فایل جدید Pages\LearnBlazor\LearnBlazorComponents\ChildComponent.razor را با محتوای زیر ایجاد میکنیم:
<div>
<div class="alert alert-info">@Title</div>
<div class="alert alert-success">
@if (ChildContent == null)
{
<span> Hello, from Empty Render Fragment </span>
}
else
{
<span>@ChildContent</span>
}
</div>
</div>
@code {
[Parameter]
public string Title { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
}
توضیحات:
- خاصیت عمومی Title که توسط ویژگی Parameter مزین شدهاست، امکان تنظیم مقدار مشخصی را توسط کامپوننت دربرگیرندهی ChildComponent میسر میکند.
- در اینجا پارامتر عمومی دیگری نیز تعریف شدهاست که اینبار از نوع ویژهی RenderFragment است. توسط آن میتوان به محتوایی که در کامپوننت والد ChildComponent در بین تگهای آن تنظیم شدهاست، دسترسی یافت. همچنین اگر این محتوا توسط کامپوننت والد تنظیم نشده باشد، مانند دومین باری که ChildComponent در صفحه قرار گرفتهاست، میتوان با بررسی نال بودن آن، یک محتوای پیشفرض را نمایش داد.
با این خروجی:
روش دیگری برای فراخوانی Event Call Back ها
در
قسمت قبل روش انتقال اطلاعات را از کامپوننتهای فرزند، به والد مشاهده کردیم. فراخوانی آنها در سمت Child Component نیاز به یک متد اضافی داشت و همچنین تنها یک پارامتر را هم ارسال کردیم. برای ساده سازی این عملیات از روش زیر نیز میتوان استفاده کرد:
<button class="btn btn-danger"
@onclick="@(() => OnClickBtnMethod.InvokeAsync((1, "A message from child!")))">
Show a message from the child!
</button>
@code {
// ...
[Parameter]
public EventCallback<(int, string)> OnClickBtnMethod { get; set; }
}
- در اینجا برای تعریف و ارسال بیش از یک پارامتر، از tuples استفاده شدهاست.
- همچنین فراخوانی OnClickBtnMethod.InvokeAsync را نیز در محل تعریف onclick@ بدون نیازی به یک متد اضافی، مشاهده میکنید. نکتهی مهم آن، قرار دادن این قطعه کد داخل ()@ است تا ابتدا و انتهای کدهای #C مشخص شود؛ وگرنه کامپایل نمیشود.
در سمت کامپوننت والد برای دسترسی به OnClickBtnMethod که اینبار یک tuple را ارسال میکند، میتوان به صورت زیر عمل کرد:
@page "/ParentComponent"
<h1 class="text-danger">Parent Child Component</h1>
<ChildComponent
OnClickBtnMethod="ShowMessage"
Title="This title is passed as a parameter from the Parent Component">
A `Render Fragment` from the parent!
</ChildComponent>
<ChildComponent Title="This is the second child component">
<p><b>@MessageText</b></p>
</ChildComponent>
@code {
string MessageText = "";
private void ShowMessage((int Value, string Message) args)
{
MessageText = args.Message;
}
}
در اینجا OnClickBtnMethod تعریف شده، به متد ShowMessage متصل شدهاست که یک tuple از جنس (int, string) را دریافت میکند. سپس با انتساب خاصیت رشتهای آن به فیلد جدید MessageText، سبب نمایش آن میشویم.
امکان تعریف چندین RenderFragment
تا اینجا یک RenderFragment را در کامپوننت فرزند تعریف کردیم. امکان تعریف چندین RenderFragment در ChildComponent.razor نیز وجود دارند:
@code {
// ...
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public RenderFragment DangerChildContent { get; set; }
}
در یک چنین حالتی، روش استفادهی از این پارامترهای RenderFragment در سمت والد (ParentComponent.razor) به صورت زیر خواهد بود:
<ChildComponent
OnClickBtnMethod="ShowMessage"
Title="This title is passed as a parameter from the Parent Component">
<ChildContent>
A `Render Fragment` from the parent!
</ChildContent>
<DangerChildContent>
A danger content from the parent!
</DangerChildContent>
</ChildComponent>
که به همراه ذکر صریح نام پارامترها به صورت تگهایی جدید، داخل تگ اصلی است.
از آنجائیکه ذکر این تگها اختیاری است، نیاز است در ChildComponent.razor بر اساس null بودن آنها، تصمیم به رندر محتوایی پیشفرض گرفت:
@if(DangerChildContent == null)
{
@if (ChildContent == null)
{
<span> Hello, from Empty Render Fragment </span>
}
else
{
<span>@ChildContent</span>
}
}
else
{
<span>@DangerChildContent</span>
}
کدهای کامل این مطلب را از اینجا میتوانید دریافت کنید: Blazor-5x-Part-08.zip