在第四章元件的介紹中,提到元件可重複使用,但是如果元件的內容都固定了要怎麼重複使用呢?
寫程式的大家都知道,看到重複的邏輯時應當要抽離成方法(Method),當一段重複的邏輯要重構成方法時,要做的步驟如下:
- 先分析類似的邏輯中哪些部分完全相同,哪些地方有一點不同
- 完全相同的部分,依樣畫葫蘆
- 有一點不同的部分,將其中變化的地方外移到參數,由外部傳入
元件也是一樣的,一個可重複使用的元件,可能會有一些地方需要變化,這時候就需要使用到參數來處理,畢竟參數本身就是值的不確定性,今天讓我們一起來認識 Blazor 元件中的參數該如何使用
參數 [Parameter]#
我們以一個簡單的元件範例來做說明,這是Bootstrap Card,有10張這樣的卡片要製作,但是不一樣的地方只有內容,此時我們就可以把這份 Card 做成 Card.razor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| <div class="card">
<div class="card-header">
@CardHeader
</div>
<div class="card-body">
<blockquote class="blockquote mb-0">
<p>@Text</p>
<footer class="blockquote-footer">@Author</footer>
</blockquote>
</div>
</div>
@code {
[Parameter]
public string CardHeader{ get; set; }
[Parameter]
public string Text{ get; set; }
[Parameter]
public string Author { get; set; }
}
|
在元件中,替公開屬性上加入 Parameter Attribute,就會被識別為參數
完成這個 Card.razor 之後,在另一個元件中可以呼叫它,看起來會像是這樣
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| @page "/ParamterSample"
<h3>ParamterSample</h3>
<Card
CardHeader="第一則"
Text="寫程式時要保持這種心態:就好像將來要維護你這些程式的人是一位殘暴的精神病患者,而且他知道你住在哪"
Author="Martin Golding">
</Card>
<Card
CardHeader="第二則"
Text="這不是個 bug——這一個未註明的功能特徵"
Author="Anonymous">
</Card>
|
在引用其他元件時需注意,元件的參數內容如果需要從C#內指派,要在被指派的成員前面加上@
符號
1
| <Card CardHeader="@Header" Text="@Text" Author="@Author"></Card>
|
參數的一點點細節#
- 參數應該要宣告為自動屬性
不應該在參數的存取子內撰寫邏輯,因為是參數的提供給父元件傳值的通道,如果在子元件存取子內有使父元件重新渲染的邏輯,這時候就會產生無窮迴圈
1
2
| [Parameter]
public string Text{ get; set; }
|
如果要操作參數的資料,另外做屬性或方法是比較好的做法
1
2
3
| <Card CardHeader="@await GetHeader" </Card>
// 'await' 運算子只能在非同步方法中使用。
// 請考慮使用 'async' 修飾詞標記這個方法,並將其傳回類型變更為 'Task'。
|
如果要從非同步的作業中取值,可以使用元件生命週期的OnInitializedAsync,寫起來會像是這樣
1
2
3
4
5
6
7
8
9
| <Card CardHeader="@title" </Card>
@code{
private string? title;
protected override async Task OnInitializedAsync()
{
title = await GetHeader();
}
}
|
生命週期也會專門做文章跟大家探討
- 不支援使用明確 Razor 運算式來串連文字與運算式結果
1
2
| <Card CardHeader="我的卡片 @(Card.Title)" </Card>
// Component attributes do not support complex content (mixed C# and markup).
|
如果要做字串連接,可以在下方code區域處理字串後在使用
參數傳遞#
父元件(Parent component) -> 子元件(Child component)#
父元件 Parent.razor
1
2
3
4
5
6
7
8
9
10
11
12
| @page "/Parent"
<h3>父子元件參數傳遞</h3>
<h4>父元件</h4>
<input class="form-control" @bind="ParentMessage">
<Child></Child>
@code {
[Parameter]
public string ParentMessage{ get; set; }
}
|
子元件 Child.razor
1
2
3
4
5
6
7
| <h4>子元件</h4>
<input value="@ChildMessage" class="form-control">
@code {
[Parameter]
public string ChildMessage{ get; set; }
}
|
打開父元件的頁面是長這樣
要在對父元件的Input
輸入時,將參數傳給子元件,做法如下
- 子元件內加入
EventCallback<T>
,T 是子元件內部接收外部參數的型別並且命名為Changed
。
父元件的 ParentMessage
參數,要傳遞到子元件內的 ChildMessage
參數,所以EventCallback
的 <T>
會是ChildMessage
的型別也就是string
,EventCallback
的參數名稱 必須 是子元件參數名稱加上Changed
,寫起來會像是這樣
1
2
| [Parameter]
public EventCallback<string> ChildMessageChanged { get; set; }
|
- 父元件中 bind 子元件內的參數即可
1
| <Child @bind-ChileMessage="ParentMessage"></Child>
|
如此就實現父傳子的功能
如果命名不想要受到 慣例(Convention) 的影響,只要將父元件的 bind 拆開處理即可
子元件(Child component) -> 父元件(Parent component)#
在子元件內加入事件,對 Input
輸入完成後,透過事件去更新子元件的欄位,去呼叫 ChildMessageChanged
,這樣的做法被稱為 鏈式綁定(Chained bind)
1
2
3
4
5
| private async Task UpdateMessageFromChild(ChangeEventArgs args)
{
ChildMessage = args.Value.ToString();
await ChildMessageChanged.InvokeAsync(ChildMessage);
}
|
我們了解了元件該怎麼設定參數,還有非常重要的參數傳遞的方法,下一章介紹元件的一生是怎麼樣過的會,來了解它的生命中會遇到什麼事件