翻譯自 Waqas Anwar 2021年3月19日的文章 《A Beginner’s Guide to Blazor Components》 [1]
Blazor 應用程序是組件的組合,這些組件不僅負責呈現用戶界面,還協同工作以促進用戶交互。它們是 Blazor 應用程序的主要構建塊,大多數 Blazor 功能都是圍繞組件展開的。在本教程中,我將向您詳細介紹組件,並向您展示在 Blazor 應用程序中創建和使用組件的多種技術。
Blazor 組件概述
Blazor 組件是 UI 的一個自包含部分,例如一個頁面、一個側邊欄菜單、一個聯系人表單或儀表盤小工具等。它包括用於呈現 UI 的 HTML 標簽和用於處理數據或處理用戶事件的 C# 代碼。組件可以相互嵌套,也可以在項目中重用,甚至可以跨多個項目重用。Blazor 組件是作為 Razor 組件實現的,這正是它們使用 Razor 語法並具有 .razor 文件擴展名的原因。
為了理解 Blazor 組件的結構及其工作方式,讓我們回顧一下 Counter.razor 組件(如果您在 Visual Studio 2019 中使用 Blazor App 模板,它會自動為我們生成)。下面是 Counter.razor 的完整代碼。
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
文件中的第一行使用了 Razor @page 指令來指定組件的路由。這意味着 Counter 組件是頁面級或可路由組件,可以在瀏覽器中使用 URL 末尾的 /counter 路徑來訪問它。如果我們不指定 @page 指令,則該組件將變為子組件,可以通過將其嵌套在其他組件中來使用它。
@page "/counter"
如下所示,我們還可以聲明多個 @page 級別的指令。這將允許我們使用兩個 URL 訪問組件。
@page "/counter"
@page "/mycounter"
在 @page 指令之后,是用於指定該組件 UI 的 HTML 標記。這些標記可以使用 Razor 語法動態地使用表達式、條件或循環來渲染 HTML。在上述的 Counter 組件示例中,其 UI 包含一個標題 (h1)、一個段落 (p) 和一個按鈕 (button) 元素。段落 (p) 元素使用 Razor 語法來輸出 C# 代碼塊中定義的 currentCount 變量的值。
<p>Current count: @currentCount</p>
按鈕 (button) 元素通過調用方法 IncrementCount 來響應用戶單擊操作,該方法也定義在代碼塊中。
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
最后,是一個代碼塊,每次調用 IncrementCount 方法時,我們簡單地將 currentCount 變量的值加 1。
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
當 Blazor 應用程序進行編譯時,HTML 標記和 C# 代碼將轉換成一個組件類,類名稱與組件的文件名相對應。該類的成員是我們在 @code 中定義的相同的變量和方法。允許使用多個 @code 塊,所有這些代碼塊在編譯后會合並進同一組件類。
在 Visual Studio 2019 中創建 Blazor 組件
如果您要創建一個頁面級組件,請右鍵單擊 Pages 文件夾並選擇 添加 > Razor 組件... 菜單選項。
您也可以在解決方案資源管理器中右鍵單擊項目名稱,然后使用 Razor 組件 模板創建一個組件。
讓我們創建一個文件名為 Calculator.razor 的組件,並添加以下代碼。
Calculator.razor
@page "/calculator"
<h3>Calculator</h3>
<div class="form-group">
<label for="number1">Number 1</label>
<input type="number" class="form-control" id="number1" @bind="number1">
</div>
<div class="form-group">
<label for="number2">Number 2</label>
<input type="number" class="form-control" id="number2" @bind="number2">
</div>
<div class="form-group">
<label><b>Total: </b>@total</label>
</div>
<button class="btn btn-primary" @onclick="Calculate">Calculate</button>
@code {
private int number1 = 0;
private int number2 = 0;
private int total = 0;
private void Calculate()
{
total = number1 + number2;
}
}
此 @code 塊具有三個私有變量和一個 Calculate 方法。Calculate 方法簡單地將 number1 和 number2 的和賦值給 total 變量。
HTML 標記中有兩個輸入框,它們使用 @bind 屬性來綁定 number1 和 number2 變量:
<input type="number" class="form-control" id="number1" @bind="number1">
變量 total 的值使用 Razor 語法 @total 渲染在頁面上:
<label><b>Total: </b>@total</label>
最后,是一個按鈕元素,它將 Calculate 方法綁定到 @onclick 事件。每當用戶點擊按鈕時,就會調用 Calculate 方法,頁面上的 total 變量的值將更新。
<button class="btn btn-primary" @onclick="Calculate">Calculate</button>
為了輕松訪問您的 Calculator 組件,可以通過在 NavMenu.razor 組件中添加以下標記,在應用程序側邊欄中添加 Calculator 組件。
<li class="nav-item px-3">
<NavLink class="nav-link" href="calculator">
<span class="oi oi-calculator" aria-hidden="true"></span> Calculator
</NavLink>
</li>
按 F5
運行您的應用程序,您應該會看到如下所示的頁面。嘗試在輸入框中輸入一些數字,您應該能看到頁面上顯示的數字之和。點擊 Calculate 按鈕運行了服務端的 C# 代碼,卻並沒有瀏覽器回傳或頁面刷新。一切都感覺那么流暢和快速,就像您在瀏覽器中使用 JavaScript 進行計算一樣。
如果您想檢驗一下代碼是在服務端上運行的,只需嘗試在 Calculate 方法中添加一個斷點,然后再次按下 F5。這次,當您點擊 Calculate 按鈕時,您將看到代碼執行到斷點處停止,您還可以在 tooltips 中看到用戶輸入,如下圖所示:
拆分 Blazor 組件中的標簽和代碼
如果您創建的是小型組件,那么您可能希望在單個 .razor 文件中編寫所有 C# 代碼;但如果您有大量的邏輯要寫並且為了更好的代碼維護,您希望將 C# 代碼與 HTML 標簽分開,那么可以通過以下兩種方式來實現。
使用基類拆分組件
使用這種方式,您可以創建一個獨立的類,該類應該從 ComponentBase 類派生。然后,您可以將組件中的屬性和方法從 @code 塊移動到這個新創建的類,最后,您可以使用 @inherits 指令來指定組件的基類。讓我們將這種方式應用於我們上面創建的 Calculator 組件。在項目中創建一個 CalculatorBase 類,並將 C# 代碼從 Calculator.razor 移動到這個新類中。
CalculatorBase.cs
public class CalculatorBase : ComponentBase
{
private int number1 = 0;
private int number2 = 0;
private int total = 0;
private void Calculate()
{
total = number1 + number2;
}
}
然后在 Calculator.razor 文件的頂部添加 @inherits 指令,如下:
Calculator.razor
@page "/calculator"
@inherits CalculatorBase
<h3>Calculator</h3>
<div class="form-group">
<label for="number1">Number 1</label>
<input type="number" class="form-control" id="number1" @bind="number1">
</div>
<div class="form-group">
<label for="number2">Number 2</label>
<input type="number" class="form-control" id="number2" @bind="number2">
</div>
<div class="form-group">
<label><b>Total: </b>@total</label>
</div>
<button class="btn btn-primary" @onclick="Calculate">Calculate</button>
@code {
}
此時如果您嘗試構建應用程序,則會遇到很多錯誤抱怨字段和方法的可訪問性。
出現上述所有錯誤的原因是 Calculator 組件繼承自 CalculatorBase 類,而我們在 CalculatorBase 類中粘貼的屬性和方法是 private。為了確保子組件可以訪問這些字段和方法,您需要將它們聲明為 public。
public class CalculatorBase : ComponentBase
{
public int number1 = 0;
public int number2 = 0;
public int total = 0;
public void Calculate()
{
total = number1 + number2;
}
}
譯者注:
💡 基類中的字段和方法改為protected
, 在.razor
中也是可以的訪問的。
💡 CalculatorBase 類必須包含在一個命名空間中,否則會報錯。
使用部分類拆分組件
Blazor 組件生成為部分類,這意味着我們可以創建一個與我們的組件同名的 partial 類,並將所有 C# 代碼移動到該部分類中。然后,此部分類將成為代碼隱藏文件,該文件中聲明的字段和屬性可在 Blazor 組件中直接使用。讓我們創建一個類 Calculator.razor.cs,並將 Calculator 的代碼放在這個新類中。
Calculator.razor.cs
public partial class Calculator
{
public int number1 = 0;
public int number2 = 0;
public int total = 0;
public void Calculate()
{
total = number1 + number2;
}
}
如果啟用了文件嵌套,您將看到 Visual Studio 會自動將組件和代碼隱藏文件顯示在一起。
再次運行應用程序,Calculator 會以前面相同的方式工作。
創建和使用子組件
Blazor 子組件是沒有 @page 指令的組件。這些組件可以使用標准的 HTML 語法包含在其他組件中。然后,我們可以通過在頁面上添加組件來構建復雜的 UI,我們甚至可以在同一個頁面上添加同一子組件的多個實例。如果一個子組件可能在多個父組件或頁面中重復使用,那么最好將它放在 Shared 文件夾中。讓我們在 Shared 文件夾中創建一個簡單的 Heading.razor 子組件,並在其中添加以下代碼。
Heading.razor
<h3>Calculator</h3>
接下來,將父組件 Calculator.razor 中的 h3 元素替換為 <Heading />
元素。運行應用程序,您會看到 h3 標題從子組件中渲染到了頁面上。
Calculator.razor
@page "/calculator"
@inherits CalculatorBase
<Heading />
<div class="form-group">
<label for="number1">Number 1</label>
<input type="number" class="form-control" id="number1" @bind="number1">
</div>
<div class="form-group">
<label for="number2">Number 2</label>
<input type="number" class="form-control" id="number2" @bind="number2">
</div>
<div class="form-group">
<label><b>Total: </b>@total</label>
</div>
<button class="btn btn-primary" @onclick="Calculate">Calculate</button>
您甚至可以通過復制和粘貼相同的 <Heading />
元素來添加子組件的多個實例。
<Heading />
<Heading />
<Heading />
現在,如果您運行應用程序,您將會在頁面上看到三個 h3
標題。
自定義帶參數的 Blazor 組件
只是生成具有相同內容的靜態組件不是很有用。如果我們可以將一些數據傳遞給組件,而不僅僅是自定義它生成的 UI,還自定義其行為或功能,那就更好了。我們可以使用參數來自定義 Blazor 組件。這些參數可以是簡單的 int
、bool
等,也可以是復雜的 Customer
、Order
等。一旦聲明了參數,我們便可以使用屬性將數據傳遞給組件。讓我們通過在 Heading 組件中聲明一個簡單的 Title 參數來學習一下這個概念。要指定一個參數,我們要將 [Parameter] 特性附加到一個屬性上。
Heading.razor
<h3>@Title</h3>
@code {
[Parameter]
public string Title { get; set; } = "Default Title";
}
我們還為 Title 屬性設置了一個默認值 Default Title,當未提供 Title 時,則顯示該默認字符串。
Visual Studio 智能感知也可以提示組件參數,因此我們不需要記憶這些參數,這很有用。
我們可以通過傳遞任意字符串作為 Title 的值來從外部自定義 Title,Heading 組件將自動渲染傳遞給它的不同字符串。
<Heading Title="Calculator" />
我們還可以使用表達式從父組件到子組件傳遞數據。讓我們創建另外一個子組件 CalculatorTotal.razor,並向其添加以下代碼。
CalculatorTotal.razor
<label><b>Total: </b>@Total</label>
@code {
[Parameter]
public int Total { get; set; }
}
現在,您可以使用我們在父 Calculator 控制器中聲明和設置的 @total 字段來傳遞 Total 的值。
Calculator.razor
@page "/calculator"
<Heading Title="Calculator" />
<div class="form-group">
<label for="number1">Number 1</label>
<input type="number" class="form-control" id="number1" @bind="number1">
</div>
<div class="form-group">
<label for="number2">Number 2</label>
<input type="number" class="form-control" id="number2" @bind="number2">
</div>
<div class="form-group">
<CalculatorTotal Total="@total"/>
</div>
<button class="btn btn-primary" @onclick="Calculate">Calculate</button>
將路由參數傳遞給 Blazor 組件
Blazor 組件還可以接受在 @page 指令中提供的來自路由模板的參數。路由器使用路由參數自動填充相應的組件參數。
讓我們看一個如何通過路由將數據傳遞給組件的示例。創建一個新的名為 MathTable.razor 的 Blazor 組件並添加以下代碼。
MathTable.razor
@page "/MathTable/{number:int}"
<h3>Math Table</h3>
<table class="table table-bordered w-25">
@for (int i = 1; i <= 10; i++)
{
<tr>
<td>@Number</td>
<td>x</td>
<td>@i</td>
<td>=</td>
<td>@(Number * i)</td>
</tr>
}
</table>
@code {
[Parameter]
public int Number { get; set; }
}
我們指定了一個帶有 int
參數 number
的路由模板:
@page "/MathTable/{number:int}"
該路由參數將自動映射到以下組件參數:
[Parameter]
public int Number { get; set; }
在 HTML 標記中,我使用 number
參數生成一個數學公式表。運行項目並嘗試在路由 URL 中傳遞不同的數字,您將看到根據每一參數值更新的數學公式表。
總結
在本教程中,我介紹了 Blazor 組件的基礎知識。我試圖用易於理解的示例來演示每個概念,以便您可以快速學習基本概念。 Blazor 組件提供的功能比我在本教程中介紹的要多得多,而且還有許多其他與 Blazor 組件相關的高級主題。在接下來的幾周里,我將嘗試寫更多關於 Blazor 的文章,因此請繼續訪問我的網站以學習有關 Blazor 的更多知識。
相關閱讀:
- Blazor Server 和 WebAssembly 應用程序入門指南
- Blazor 組件入門指南
- Blazor 數據綁定開發指南
- Blazor 事件處理開發指南
- Blazor 組件之間使用 EventCallback 進行通信
- Blazor 路由及導航開發指南
- Blazor 模板化組件開發指南
- Blazor Server 應用程序中進行 HTTP 請求
- Blazor WebAssembly 應用程序中進行 HTTP 請求
- Blazor 組件庫開發指南
https://www.ezzylearning.net/tutorial/a-beginners-guide-to-blazor-components A Beginner’s Guide to Blazor Components ↩︎