1.元件生命週期
- SetParameterAsync 初始化前
- OnInitialized(Async) 初始化
- OnParametersSet(Async) 設定參數後
- OnAfterRender(Async) 渲染後
(1) SetParameterAsync(設定參數時,初始化之前)
使用時機 : 第一次使用組件時,會先建立這個組件的執行個體
- 第一次要求轉譯組件時,將會觸發OnInitialized生命週期事件
- 執行屬性注入,這代表在轉譯樹狀結構中設定組件父系所提供的參數
(2) OnInitialized & OnInitializedAsync
使用時機 : SetParameterAsync進行初始化時被調用
在轉譯樹狀結構中從其父系收到其初始參數。
OnInitialized 同步
protected override void OnInitialized()
{
...
}
OnInitializedAsync 異步
protected override async Task OnInitializedAsync()
{
await ...
}
(3) OnParametersSet & OnParametersSetAsync
OnParametersSet 則是在OnInitialized後執行一次,再來是每次只要Parameter有異動,就會執行一次
使用時機 :
- 當 OnInitialized/OnInitializedAsync 組件初始化執行結束後
- 組件加載之後如果參數發生改變時 ->可能被重複調用的第一對方法
- 父組件重新渲染並提供新參數時
-
此時間點代表組件已經初始化完成
設定參數前
public override async Task SetParametersAsync(ParameterView parameters)
{
await ...
await base.SetParametersAsync(parameters);
}
設定參數後 同步
protected override void OnParametersSet()
{
...
}
設定參數後 非同步
protected override async Task OnParametersSetAsync()
{
await ...
}
(4) OnAfterRender & OnAfterRenderAsync(在Html都載入完畢後觸發)
使用時機 :
- 第一次轉譯組件實例
- 有事件產生時,每次轉譯組件之後叫用的方法。例如:點擊按鈕,參數更改時。
- 完成渲染後調用
- 如果要使用第三方的 JavaScript 來存取 DOM,在此階段能正確取得
(5) 其他-ShouldRender
使用時機 : 每次轉譯組件就會呼叫
- ShouldRender 方法將會用於傳回布爾值(預設回傳true),指出元件是否應該要進行轉譯處理動作。
- 如果想要避免使用者操作產生的渲染時,可以覆寫此方法來防止 UI 重新渲染,也就是可以確保渲染樹一定是從初始化產生的。
- Return false,會阻止重新計算組件的RenderTree,禁止UI刷新。就不會觸發OnAfterRender
protected override bool ShouldRender()
{
return false;
}
(6) 其他-產生渲染樹 BuildRenderTree
使用時機 : 如果ShouldRender 是true,就會將組件的內容呈現到畫面中
- 接收渲染輸出
- 此時間點代表組件已經完成渲染。此時 DOM 就已經畫好了
(7) 其他-Dispose
使用時機 : 移除組件時觸發
@implements IDisposable
@code{
void IDisposable.Dispose()
{
Console.WriteLine(“組件銷毀");
}
}
(8) 其他-StateHasChanged 狀態變更
- 一般來說,所有的 EventCallback 方法都會自動呼叫 StateHasChanged,來通知UI進行變更。
- 但有時 Blazor 無法意識到狀態的變化,例如:何時被計時器觸發。這時需要手動調用 StateHasChanged 來通知 Blazor 某些參數已經被更改。表示向 Blazor渲染請求一個重新渲染,然後才觸發 OnAfterRender 和OnAfterRenderAsync
執行順序
載入畫面時:
1.SetParametersAsync->2.OnInitialized->3.OnParametersSetcount->4.OnAfterRender
執行點擊事件,改變變數內容
執行click->5.ShouldRender->4.OnAfterRender
父組件重新渲染並提供新參數時
執行click->5.ShouldRender->3.OnParametersSetAsync (子的)->4.OnAfterRender
點擊按鈕,父組件更改父組件屬性
5.ShouldRender->4.OnAfterRender
點擊按鈕,父組件更改子組件屬性
執行click->5.ShouldRender (父的)->1.SetParametersAsync (子的) - >3.OnParametersSetAsync (子的)->5.ShouldRender (子的)->4.OnAfterRender (父的)- >4.OnAfterRender (子的)
點擊按鈕,狀態變更 StateHasChanged
5.ShouldRender (子的)->4.OnAfterRender (子的)
點擊按鈕,頁面沒有變化
5.ShouldRender (子的)->4.OnAfterRender (子的)
2.Component Parameters 父傳參數給子
父組件要傳遞資料給子組件的作法,是透過Parameter傳遞,子組件可以透過Paramter屬性取得資料。
注:
- 子組件不可以跟父組件在同一層
- 若組件之間namespace不同,要使用 @using
@using 補充
將@using
指示詞新增至父組件或是_Imports.razor
。即可讓資料夾中的 Components 組件可供使用,例:@using BlazorSample.Components
將父組件FatherComponent.razor的data傳給子組件ChildComponent.razor
在父組件上設定按鈕上的字為send to child data
btnText="send to child data
"
子元件屬性="父組件變數"
[Parameter]
為組件參數,會將資料傳遞至組件
- 子組件設置
@變數
,並透過透過[Parameter]
將變數傳出- 父組件透過
@using
使用子組件- 父組件以HTML標籤方式引用子組件,並從父元件帶值給子組件
例:建立一個 ChildComponent.razor 和 ChildComponent.razor.cs文件
1. ChildComponent.razor
<Button Type="primary">@btnText</Button>
2.ChildComponent.razor.cs
using Microsoft.AspNetCore.Components;
namespace BlazorApp.Pages.Mybtn
{
public partial class Mybtn
{
[Parameter]
public string? btnText { get; set;}
//透過[Parameter]將btnText傳出
}
}
建立一個FatherComponent.razor 和 FatherComponent.razor.cs文件
1.FatherComponent.razor
@page "/fathercomponent";
@using BlazorApp.Pages.Mybtn;
// 1.透過@using使用子組件(Pages裡面的Mybtn資料夾)
<h2>父傳參數給子</h2>
<div class="box">
<Mybtn btnText="send to child data"></Mybtn>
//2.使用子組件class名稱當作父組件html標籤
//3.帶入參數 btnText="send to child data"
</div>
2.FatherComponent.razor.cs
namespace BlazorApp.Pages.FatherComponent
{
public partial class FatherComponnet
{
}
}
3.子組件發生事件時執行父組件的方法
- 使用
EventCallback
。 父組件可以將回呼方法指派給子組件的EventCallback
。 MouseEventArgs
鼠標的事件引數類型。e
為自定義名稱的事件參數,例:
可藉由e取得當下點擊的座標位置。-
private string? message; private void MouseClick(MouseEventArgs e) { message = $"點擊的座標({e.ScreenX}:{e.ScreenY})"; }
基礎Parameter應用
子組件(按鈕)發生點擊事件時,父組件執行方法,使畫面秀出點擊座標
OnClickCallback="@ShowMessage"
子的屬性="@父的方法"
MouseEventArgs
需要using Microsoft.AspNetCore.Components.Web
定義一個子組件 Child.razor
(1)Child.razor
<Button @onclick="OnClickCallback">
點擊
</Button>
(2) Child.razor.cs
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
//MouseEventArgs需要using Microsoft.AspNetCore.Components.Web
namespace BlazorApp.Pages.Child
{
public partial class Child
{
[Parameter]
public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
//1. 宣告OnClickCallback這個方法
//1. 因為是click事件 所以使用相對應的 MouseEventArgs
//2. 透過[Parameter]及EventCallback將方法傳出
}
}
建立一個父組件Parent.razor
@page "/parent"
@using BlazorApp.Pages.Child;
<div class="box">
<Child OnClickCallback="@ShowMessage">
</Child>
//1.這裡把父的方法 連結 子的屬性
<p>@message</p>
</div>
Parent.razor.cs
using Microsoft.AspNetCore.Components.Web;
namespace BlazorApp.Pages.Parent
{
public partial class Parent
{
private string? message;
private void ShowMessage(MouseEventArgs e)
{
message = $"點擊的座標({e.ScreenX}:{e.ScreenY})";
}
//在父組件建立父的方法
}
}
2.循環子組件,根據子組件的序列值來操作
建立一個子組件 TodoChild.razor
TodoChild.razor
<tr class="child">
<td>@ItemName</td>
<td><Button @onclick="Delete" danger>Delete</Button></td>
<!-- 定義Delete的方法 -->
</tr>
TodoChild.razor.cs
using Microsoft.AspNetCore.Components;
namespace BlazorApp.Pages.TodoChild
{
public partial class TodoChild
{
[Parameter]
public string? ItemName { get; set; }
//1.子組件宣告ItemName
[Parameter]
public int ItemIndex { get; set; }
//2.子組件宣告ItemIndex
//TodoList.Count -> 第 i 個 = ItemIndex
[Parameter]
public EventCallback<int> DeleteItem { get; set;}
//3.宣告DeleteItem方法
//3.透過EventCallback將方法傳出
//4.定義方法內容
void Delete()
{
DeleteItem.InvokeAsync(ItemIndex);
//5.透過InvokeAsync(ItemIndex)調用父組件的回調方法
}
}
}
建立父組件TodoParent.razor
@using BlazorApp.pages.TodoChild
<div class="box">
<h3>TodoList</h3>
<input type="text" @bind="newTodoItem" />
<!-- 綁定使用者輸入的內容 -->
<Button Type="primary" @onclick="Add">Add</Button>
<!-- 點擊按鈕觸發Add事件 -->
<table>
<tr>
<th>待辦事項</th>
<th>刪除</th>
</tr>
@for (int i = 0; i < TodoList.Count; i++)
{
<TodoChild ItemName="@TodoList[i]" ItemIndex="@i" DeleteItem="@DeleteCallback"/>
<!-- 引用子組件,並將DeleteCallback綁定子屬性DeleteItem -->
}
</table>
</div>
TodoParent.razor.cs
using Microsoft.AspNetCore.Components.Web;
namespace BlazorApp.Pages.TodoParent
{
public partial class Parent
{
//=============================範例二
private string? newTodoItem;
//宣告newTodoItem (input綁定的值)
private List<string> TodoList = new List<string>();
//宣告TodoList
protected override void OnInitialized()
{
TodoList = new List<string>()
{
"Buy Milk",
"Buy Apple"
};
//宣告TodoList的物件內容
}
void Add()
{
if (!string.IsNullOrEmpty(newTodoItem))
{
TodoList.Add(newTodoItem);
//TodoList 增加一個 input輸入的值
newTodoItem = "";
}
}
void DeleteCallback(int index)
{
TodoList.RemoveAt(index);
}
}
}
繼承子組件事件,父組件延伸事件內容
父組件要使用按鈕子組件,並加上自訂方法
- 子元件建立一個
點擊事件
- 子元件透過
[Parameter]
及EventCallback
設定一個呼叫端的屬性 點擊事件
做兩件事- 共同要做的事情
- 各父元件自定義的事情
(使用InvokeAsync
調用父組件的回調方法)await 呼叫端的屬性名稱.InvokeAsync(e);
- 父元件透過HTML標籤將
呼叫端的屬性
綁定父元件方法A
- 父元件
A方法
呼叫B方法
建立一個button的子組件
Mybtn.razor
<a class="@btnStyle" @onclick="Toggle">點擊會跳出父組件的Console</a>
@* //1.按鈕組件的按鈕內容為變數 *@
//Toggle function名稱
Mybtn.razor.cs
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
// namespace
namespace BlazorApp.Pages.Mybtn
{
public partial class Mybtn
{
string btnStyle = "btn-blue";
[Parameter]
public EventCallback<MouseEventArgs> OnClickCallback { get; set;}
//1.設定一個呼叫端的"屬性" -> OnClickCallback
public async Task Toggle(MouseEventArgs e)
//2.Toggle事件處理方法
{
btnStyle = btnStyle == "btn-blue" ? "btn-green" : "btn-blue";
//3.子組件必要的function內容
await OnClickCallback.InvokeAsync(e);
//4.使用InvokeAsync調用父組件的回調方法
//4.這裡可以調用父組件自定義的fucntion
//4.InvokeAsync(Object)
}
}
}
父組件ParentBtn.razor
<div class="box">
<h3>範例三 - 繼承子組件事件,父組件延伸事件內容</h3>
<Mybtn OnClickCallback="@ConsoleWord"></Mybtn>
</div>
ParentBtn.razor.cs
using Microsoft.AspNetCore.Components.Web;
namespace BlazorApp.Pages.ParentBtn
{
public partial class ParentBtn
{
//=============================範例三
void Aa()
{
Console.WriteLine("parent的方法");
//1.定義父組件自訂一的function內容
}
public void ConsoleWord(MouseEventArgs e)
{
//2.透過屬性綁定的Parent呼叫Aa()函式
Aa();
}
}
}
4.Cascading Paramater
- CascadingValue 組件,包裝底下所有組件階層,並將單一值提供給其子樹狀結構中的所有組件。
- 上層組件透過CascadingValue把值傳出
- 下層[CascadingParamter]屬性接收傳來的值
傳遞多個參數,透過按鈕改變顏色及大小
子層MainLayout.razor
@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<CascadingValue Value="@state" >
<article class="content px-4">
@Body
</article>
</CascadingValue>
</main>
</div>
@code{
State2 state = new State2();
public class State2
{
public string? color { get; set; } = "pink";
public string? size { get; set; } = "20px";
}
}
父層ParentMenu.razor
@page "/ParentMenu"
@using Syncfusion.Blazor.Diagrams
@using BlazorApp.Pages
<h2>5-4 Cascading Parameter的運用</h2>
<div class="box">
<p style="color:@state.color;font-size:@state.size">測試文字</p>
<button style="background:@state.color;font-size:@state.size;color:white;" class="btn btn-sm">測試按鈕</button>
<hr>
<h4>選擇顏色:</h4>
@foreach (var item in new string[] { "pink", "blue", "green" })
{
<div>
<input type="radio" id="@item" name="colorRadio" value="@item" @onchange="ColorRadioSelection">
<label for="@item">@item</label>
</div>}
<br />
<h4>選擇文字大小:</h4>
@foreach (var item in new string[] { "16px", "20px", "40px" })
{
<div class="custom-control custom-radio">
<input type="radio" id="@item" name="sizeRadio" value="@item" @onchange="SizeRadioSelection">
<label for="@item">@item</label>
</div>
}
</div>
@code {
[CascadingParameter]
public MainLayout.State2 state { get; set; } = null!;
void ColorRadioSelection(ChangeEventArgs args)
{
state.color = args.Value.ToString();
Console.WriteLine(args.Value.ToString());
}
void SizeRadioSelection(ChangeEventArgs args)
{
state.size = args.Value.ToString();
}
}