一.前言
在第一篇文章中,有提到過元件(Component)這個概念。元件在 Blazor 中是必不可少的,UI 全靠它組裝起來,和前端的 JS 元件是一個意思,比如:vue component、react component 等等。借用官方文件的描述:
Blazor 應用是使用元件構建的。 元件是自包含的使用者介面 (UI) 塊,例如頁、對話方塊或窗體。 元件包含插入資料或響應 UI 事件所需的 HTML Tag和處理邏輯。 元件非常靈活且輕量。 可在專案之間巢狀、重複使用和共享。
二.元件
元件一般以 .razor 為檔名字尾,且元件名必須以大寫字母開頭(猜測可能是和VUE裡的命名限制一樣,表面和Html標籤名重複)。
我們新建的專案,Shared 資料夾中就有三個元件:
左側導航選單元件:
在主佈局元件中應用了導航選單元件:
更多關於元件的資料請查閱官方文件:建立和使用 ASP.NET Core Razor 元件
三.資料繫結
1.介紹
Razor 元件通過名為 @bind
的HTML元素屬性提供資料繫結功能,這個繫結是雙向的。
@bind
是區分大小寫的,例如:@BIND
、@Bind
都是錯誤的,下面寫了一個例子,將 CurrentValue
繫結到兩個文字框中。
<div class="row">
<div class="col-6">
<input class="form-control" type="text" @bind="CurrentValue" />
</div>
<div class="col-6">
<input class="form-control" type="text" @bind="CurrentValue" />
</div>
</div>
<div class="row">
<button class="btn btn-primary" @onclick="ChangeValue">變 更</button>
</div>
@code
{
public int CurrentValue { get; set; } = 0;
private void ChangeValue()
{
CurrentValue ++;
}
}
需要注意的是在文字框的繫結中,僅當呈現元件時,UI才會更新文字框,而不響應於更改屬性的值。由於元件是在事件處理程式程式碼執行後呈現的,因此屬性更新通常在觸發事件處理程式後立即反映在UI中。
@bind="CurrentValue"
等同於以下程式碼:
<input value="@CurrentValue"
@onchange="@((ChangeEventArgs __e) => CurrentValue =
__e.Value.ToString())" />
@code {
public int CurrentValue { get; set; } = 0;
}
點選按鈕,變更了值,也會應用到文字框中:
2.變更繫結事件
上面小節中,預設繫結了 onchange
事件,只有文字框失去焦點才會觸發,體驗不是很好,那麼可不可以在輸入的時候就同步更新值呢,當然是可以的,解決方案就是變更繫結事件為 oninput
,通過設定@bind:event
屬性來變更繫結事件:
<div class="col-6">
<input class="form-control" type="text" @bind="CurrentValue" @bind:event="oninput" />
</div>
<div class="col-6">
<input class="form-control" type="text" @bind="CurrentValue" @bind:event="oninput" />
</div>
3.輸入錯誤的值
我們設定的 CurrentValue 的型別是 int ,如果我們輸入字母,那麼字母將不會被接受,同時值會恢復到輸入前的正確值。
4.子父元件資料傳遞
在 vue、react 等 js 中,都有子父元件傳值概念,Blazor 也不例外。
(1)父傳子
新建一個子元件命名為 ChildComponent
<div class="row">
<h2>子元件</h2>
</div>
<div class="row">
<span>Year: </span> <input class="form-control" type="text" value="@Year" />
</div>
@code {
[Parameter]
public int Year { get; set; }
[Parameter]
public EventCallback<int> YearChanged { get; set; }
}
定義一個 Year
屬性和 EventCallback<int>
型別的屬性 YearChanged
新建一個父元件命名為ParentComponent
<div class="row">
<h2>父元件</h2>
</div>
<div class="row">
<span>ParentYear: </span> <input class="form-control" type="text" @bind="ParentYear" @bind:event="oninput"/>
</div>
<ChildComponent @bind-Year="ParentYear" />
@code {
[Parameter]
public int ParentYear { get; set; } = 1978;
}
在頁面中引用父元件:
YearChanged
是一個約定命名,不能更改,更改將會報錯:
EventCallback 用於子父元件巢狀時公開事件,比如 YearChanged 就公開了子元件 Year 屬性的 changed 事件。父元件裡,通過 @bind-Year
來繫結 Year
的 changed 事件,然後將父元件 ParentYear
的值傳遞過去,達成父級元件向子級元件傳遞值。
<ChildComponent @bind-Year="ParentYear" />
等同於 <ChildComponent @bind-Year="ParentYear" @bind-Year:event="YearChanged" />
,如果使用後者,那麼事件命名將不會受約定命名限制。
執行效果:
(2)子傳父(鏈式繫結)
子傳父,無法直接通過 @bind
來實現,需要單獨指定事件處理程式和值,我們更改上面的子元件,定義一個 OnYearChanged
事件,並將其繫結到文字框的 oninput
事件,在事件裡手動更新了 Year的值,並呼叫 YearChanged 來進行傳遞。
<div class="row">
<h2>子元件</h2>
</div>
<div class="row">
<span>Year: </span> <input class="form-control" type="text" @oninput="OnYearChanged" value="@Year" />
</div>
@code {
[Parameter]
public int Year { get; set; }
[Parameter]
public EventCallback<int> YearChanged { get; set; }
private Task OnYearChanged(ChangeEventArgs e)
{
Year = int.Parse(e.Value.ToString());
return YearChanged.InvokeAsync(Year);
}
}
執行: