Blazor 數據綁定開發指南
翻譯自 Waqas Anwar 2021年3月21日的文章 《A Developer』s Guide to Blazor Data Binding》 [1]
現如今,大多數 Web 應用程序要麼是在頁面上顯示某種數據,要麼是使用表單從用戶那裡收集數據。這意味着每個 SPA 框架都必須支持數據綁定,以便開發者可以將數據與 label
、form
控件等元素進行綁定。Blazor 組件內置了對數據綁定的支持,還使用了多種技術來同時支持單向和雙向數據綁定。在本教程中,我將通過一個簡單的卡片設計器示例來介紹 Blazor 數據綁定功能的基礎知識,在該示例中,用戶能夠查看其卡片設計的實時更新情況。
單向綁定
在單向數據綁定中,數據沿一個方向傳遞。應用程序代碼更新值以響應某些事件或用戶操作,當值更新時,相應的 UI 也會動態更新。單向數據綁定中,不允許用戶直接更改值。在 Blazor 中,我們通常使用 @
符號後跟屬性、字段,甚至是一個方法來實現單向數據綁定。例如,如果您的代碼中有一個 Title 屬性,並且您想將它與一個 h1 元素綁定,那麼您可以編寫類似以下代碼段的代碼。
<h1>@TItle</h1>
現在,要更新上述代碼中的 Title,您可以使用一個簡單的按鈕 onclick 事件,調用代碼中的 UpdateTitle 方法來更新 Title 屬性的值。因為一旦用戶點擊按鈕,更新的值便自動從代碼傳遞到用戶界面,所以 h1 元素的文本將會自動更新。
<button @onclick="UpdateTitle">Update Title</button>
@code{
public string Title { get; set; } = "Hello";
private void UpdateTitle()
{
Title = "Hello, Blazor!";
}
}
雙向綁定
在雙向數據綁定中,數據是雙向流動的。通常,用戶在前端以某種形式更新某個值,該值在後端代碼中自動更新,然後這個新值再傳遞到 UI 並更新綁定到該值的所有元素。在 Blazor 中,可以使用 @bind 特性實現雙向數據綁定,該特性能夠以多種方式使用。下面的簡單示例演示了 @bind 特性的基本用法,在這個示例中我們使用 @bind=Property 語法將 Title 屬性與 input
元素進行綁定。
<h1>@Title</h1>
<input @bind="Title" />
@code {
public string Title { get; set; } = "Blazor";
}
我們還可以將某一屬性綁定到特定的事件,以便僅在特定的事件觸發時才更新該屬性的值。綁定到特定事件的語法是 @bind:event=”EVENT NAME”。例如,在下面的代碼段中,我希望僅在用戶將焦點從輸入框移開時才改變 Title 屬性。
<h1>@Title</h1>
<input @bind="Title" @bind:event="onchange" />
@code {
public string Title { get; set; } = "Blazor";
}
現在我們已經掌握了 Blazor 數據綁定的基礎知識,那麼,在接下來的教程中,我將向您展示一些使用數據綁定的真實示例。在我們開始之前,請確保您已熟悉了創建和使用 Blazor 組件。如果您不了解如何創建 Blazor 應用程序或組件,我建議您閱讀我之前的文章 Blazor 組件入門指南。
入門實例
在 Visual Studio 2019 中創建一個 Blazor Server 應用,並在 Pages 文件夾中添加一個新的 Blazor 組件 CardDesigner.razor。 我們想要構建一個簡單的卡片設計器頁面,允許用戶同時設計和預覽卡片。 讓我們在新建組件的 razor 視圖中添加以下 HTML 標記。
CardDesigner.razor
@page "/"
<h1>Card Designer (Blazor Data Binding)</h1>
<div class="container">
<div class="row">
<div class="col-8">
<h3>Design</h3>
<form>
<div class="form-group">
<label for="Heading">Heading</label>
<input type="text" class="form-control" id="Heading">
</div>
<div class="form-group">
<label for="Description">Description</label>
<textarea class="form-control" id="Description" rows="4"></textarea>
</div>
<button class="btn btn-secondary mb-2">Reset</button>
</form>
</div>
<div class="col-4">
<h3>Preview</h3>
<div class="card bg-light w-100">
<div class="card-header">
Heading
</div>
<div class="card-body">
<p class="card-text">
Description
</p>
</div>
</div>
</div>
</div>
</div>
為了確保我們的卡片設計器看起來賞心悅目,您還需要在 wwwroot/css/site.css 文件中添加一些基本的 CSS 樣式。
site.css
.container {
margin: 15px;
padding: 0px;
}
.col-8, .col-4 {
border: 1px solid #dadada;
padding: 10px;
}
h1 {
font-size: 22px;
font-weight: bold;
margin-bottom: 30px;
margin-top: 20px;
}
h3 {
font-size: 18px;
font-weight: bold;
margin-bottom: 25px;
}
運行該應用程序,您應該能看到類似以下內容的頁面。左手邊是設計部分,允許用戶設置卡片的 Heading 和 Description,右手邊顯示卡片預覽。還有一個 Reset 按鈕,可以將表單重置為默認值。
讓我們為卡片設計器的實現邏輯創建一個單獨的代碼隱藏部分類(partial class)。該類有兩個簡單的帶有默認值的屬性 Heading 和 Description。還有一個 ResetCard 方法,當用戶點擊 Reset 按鈕時會調用此方法,將兩個屬性重置為其默認值。
CardDesigner.razor.cs
public partial class CardDesigner
{
public string Heading { get; set; } = "Heading";
public string Description { get; set; } = "Description";
public void ResetCard(MouseEventArgs e)
{
Heading = "Heading";
Description = "Description";
}
}
單向綁定實例
現在,我們已為查看 Blazor 數據綁定功能的實際應用做好了準備。讓我們先從單向數據綁定開始。稍微更新一下上面的 <form>
代碼,並使用 @
符號和屬性名添加單向綁定。我將 input
和 textarea
元素的 value 特性(attribute)綁定到 Heading 和 Description 屬性(property),然後添加 @onchange 事件,使用 Lambda 表達式語法更改 Heading 屬性。還將 ResetCard 方法附加到了 Reset 按鈕的 onclick 事件。
CardDesigner.razor
<form>
<div class="form-group">
<label for="Heading">Heading</label>
<input type="text" class="form-control" id="Heading" value="@Heading"
@onchange="@(e => { Heading = e.Value.ToString(); })">
</div>
<div class="form-group">
<label for="Description">Description</label>
<textarea class="form-control" id="Description" rows="4"
@onchange="@(e => { Description = e.Value.ToString(); })" value="@Description"></textarea>
</div>
<button type="button" class="btn btn-secondary mb-2" @onclick="ResetCard">Reset</button>
</form>
我們還需要使用單向數據綁定更新預覽部分的卡片,以便每次代碼中的 Heading 或 Description 更新時,預覽部分都會自動在卡片上渲染更新後的值。
CardDesigner.razor
<div class="card text-white w-100 @SelectedStyleCssClass">
<div class="card-header">
@Heading
</div>
<div class="card-body">
<p class="card-text">
@Description
</p>
</div>
</div>
現在,如果您運行應用程序,您將會看到類似於下面的輸出。嘗試在設計區輸入標題和描述,您會注意到,當您將焦點從輸入框移開時,預覽區會立即自動更新。
如果您不喜歡在 HTML 中使用 Lambda 表達式,您還可以在代碼中定義 UpdateHeading 和 UpdateDescription 方法,然後將這些方法與 @onchange 事件關聯起來。
CardDesigner.razor
<form>
<div class="form-group">
<label for="Heading">Heading</label>
<input type="text" class="form-control" id="Heading" value="@Heading"
@onchange="UpdateHeading">
</div>
<div class="form-group">
<label for="Description">Description</label>
<textarea class="form-control" id="Description" rows="4"
value="@Description"
@onchange="UpdateDescription"></textarea>
</div>
<button type="button" class="btn btn-secondary mb-2" @onclick="ResetCard">Reset</button>
</form>
CardDesigner.razor.cs
public partial class CardDesigner
{
public string Heading { get; set; } = "Heading";
public string Description { get; set; } = "Description";
public void ResetCard(MouseEventArgs args)
{
Heading = "Heading";
Description = "Description";
}
public void UpdateHeading(ChangeEventArgs e)
{
Heading = e.Value.ToString();
}
public void UpdateDescription(ChangeEventArgs e)
{
Description = e.Value.ToString();
}
}
雙向綁定實例
截至目前,我們僅在應用程序中使用了單向綁定,因為 Heading 和 Description 屬性的值是在我們的代碼中更新的,而且我們的代碼只在用戶將焦點從表單控件移開時才執行。讓我們更新一下示例的代碼,看看如何在該示例中使用雙向數據綁定。使用 @bind 特性將 Heading 和 Description 屬性與表單控件綁定。我還希望當用戶開始在表單控件中打字時立即更新卡片預覽。為此,請將 @bind:event=”oninput” 添加到了 input
和 textarea
控件。
CardDesigner.razor
<form>
<div class="form-group">
<label for="Heading">Heading</label>
<input type="text" class="form-control" id="Heading" @bind="Heading" @bind:event="oninput">
</div>
<div class="form-group">
<label for="Description">Description</label>
<textarea class="form-control" id="Description" rows="4" @bind="Description" @bind:event="oninput"></textarea>
</div>
<button type="button" class="btn btn-secondary mb-2" @onclick="ResetCard">Reset</button>
</form>
現在,雙向綁定已經設置好了,因此我們不再需要手動更新屬性,這樣我們就可以將 UpdateHeading 和 UpdateDescription 方法從代碼中刪除。
CardDesigner.razor.cs
public partial class CardDesigner
{
public string Heading { get; set; } = "Heading";
public string Description { get; set; } = "Description";
public void ResetCard(MouseEventArgs args)
{
Heading = "Heading";
Description = "Description";
}
}
再次運行應用程序並在設計表單中輸入標題和描述,看下卡片預覽是如何自動更新的。
讓我們進一步擴展我們的示例,在設計區引入一個下拉列表控件。該下拉列表將顯示不同的卡片樣式,用戶能夠使用雙向數據綁定即時地選擇和應用任一卡片樣式。讓我們在 Data 文件夾中添加以下 StyleInfo 類。
StyleInfo.cs
public class StyleInfo
{
public string Name { get; set; }
public string CssClass { get; set; }
}
讓我們在 CardDesigner.razor.cs 文件中再添加兩個屬性來存儲可用卡片樣式的列表,並存儲所選樣式的引用。我們在名為 OnInitialized 的組件初始化方法中初始化 Styles 屬性。在從父組件接收到初始化參數後,組件會進行初始化,初始化完成時將調用 OnInitialized 方法。
CardDesigner.razor.cs
public partial class CardDesigner
{
public string Heading { get; set; } = "Heading";
public string Description { get; set; } = "Description";
public List<StyleInfo> Styles { get; set; }
public string SelectedStyleCssClass { get; set; }
protected override void OnInitialized()
{
Styles = new List<StyleInfo>()
{
new StyleInfo() { Name = "Primary", CssClass = "bg-primary" },
new StyleInfo() { Name = "Secondary", CssClass = "bg-secondary" },
new StyleInfo() { Name = "Success", CssClass = "bg-success" }
};
SelectedStyleCssClass = "bg-primary";
}
public void ResetCard(MouseEventArgs args)
{
Heading = "Heading";
Description = "Description";
}
}
最後,我們需要在 CardDesigner.razor 文件中添加一個 HTML select
元素。我們運行一個簡單的 @foreach 循環來迭代 Styles 屬性,並在循環中創建 <option>
元素。每個 <option>
元素的 value 特性使用 CssClass 屬性值呈現,每個 <option>
元素的文本使用 Name 屬性值呈現。
CardDesigner.razor
<div class="form-group">
<label for="Style">Style</label>
<select class="form-control" id="Style" @bind="SelectedStyleCssClass" @bind:event="onchange">
@foreach (var style in Styles)
{
<option value="@style.CssClass">@style.Name</option>
}
</select>
</div>
在上面的代碼片段中,我們使用 @bind 特性將 SelectedStyleCssClass 屬性與 select
元素綁定,並指定使用 select
的 onchange 事件,以便每次用戶從下拉列表中選擇一個選項時,卡片樣式自動更新。
現在,如果您運行項目,將會看到下拉列表中填充的樣式,並且選中的樣式會應用到預覽部分的卡片。
右鍵點擊 select
元素並選擇 檢查(Inspect) 菜單選項,可以查看 option
是如何渲染在 HTML 中的,以及每個 option
的 value 是如何包含我們在代碼中初始化的 CssClass 屬性的。
試試從下拉列表中選擇不同的樣式,卡片預覽會立即更新。
總結
在本教程中,我介紹了 Blazor 數據綁定的基礎知識。我們學習了如何使用單向和雙向數據綁定功能,以及如何使用數據綁定更新值。我們還學習了如何利用不同的事件來指定何時更新值。在 Blazor 中還有一些更高級的數據綁定概念,我將盡最大的努力就這個主題再寫幾篇文章。
相關閱讀:
-
//www.ezzylearning.net/tutorial/a-developers-guide-to-blazor-data-binding A Developer』s Guide to Blazor Data Binding ↩︎