注意
這不是這篇文章的最新版本。 關於目前版本,請參閱 本文的 .NET 10 版本。
警告
不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支持原則。 如需目前的版本,請參閱 本文的 .NET 9 版本。
本文說明如何在 Razor 應用程式中建立和使用 Blazor 元件,包括 Razor 語法、元件命名、命名空間和元件參數的指引。
Razor 元件
Blazor 應用程式會使用 Razor 元件來建置 (非正式的名稱為 Blazor 元件,或僅稱 元件)。 元件是使用者介面 (UI) 的獨立部分,具有處理邏輯而能夠啟用動態行為。 元件可巢狀處理、重複使用、在專案之間共用,以及用於 MVC 和 Razor Pages 應用程式。
元件會轉譯為瀏覽器文件物件模型 (DOM) 的記憶體內部表示法,這個表示法稱為「轉譯樹」,可用來以彈性且有效率的方式更新 UI。
雖然「Razor 元件」與其他 ASP.NET Core 內容轉譯技術共用一些命名,但 Razor 元件必須與 ASP.NET Core 中的下列不同功能區別:
重要
當使用 Blazor Web App時,大部分 Blazor 文件範例元件 需要 互動功能,才能運作,還會示範文章裡頭涵蓋的概念。 互動 讓用戶能夠與渲染的元件互動。 這包括應用程式對 檔物件模型(DOM) 事件的回應,以及透過 Blazor事件處理程序和系結,將狀態變更連結到 C# 成員。 當您在 Blazor Web App中測試文章所提供的範例元件時,請確定應用程式採用全域互動功能,或元件採用互動式渲染模式。 本主題的詳細資訊是由 ASP.NET Core Blazor轉譯模式提供,這是目錄中本文之後的下一篇文章。
元件類別
元件會使用 C# 和 HTML 標記的組合,實作到副檔名為 Razor 的 .razor 元件檔案中。
ComponentBase 是 Razor 元件檔案所描述元件的基底類別。 ComponentBase 會實作元件的最低抽象概念,即 IComponent 介面。 ComponentBase 會定義基本功能的元件屬性和方法,例如,處理一組內建元件生命週期事件。
ComponentBase 在 dotnet/aspnetcore 參考來源中:參考來源包含有關內建生命週期事件的其他備註。 不過,請記住,元件功能的內部實作可能隨時有所變更,恕不另行通知。
注意
.NET 參考原始碼的文件連結通常會載入存放庫的預設分支,這代表著目前針對下一版 .NET 的開發進度。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤。
開發人員通常會從 Razor 元件檔案 (Razor) 建立 .razor 元件,或以 ComponentBase 做為其元件的基礎,但也可以實作 IComponent 來建置元件。 實作 IComponent 的開發人員建置元件可以對轉譯進行低階控制,但代價是必須手動觸發由開發人員自行建立及維護的事件及生命週期方法。
Blazor 文件範例程式碼和樣本應用程式採用的其他慣例可在 ASP.NET Core Blazor 基礎知識中找到。
Razor 語法
元件會使用 Razor 語法。 元件廣泛使用兩個 Razor 功能,分別是「指示詞」和「指示詞屬性」。 這些是帶有 @ 前綴並出現在 Razor 標記中的保留關鍵字:
指令:變更元件標記的編譯或功能。 例如,
@page指示詞會指定使用者只要透過瀏覽器在特定 URL 中提出要求,即可直接連線具有路由範本的可路由元件。依照慣例,元件定義 (
.razor檔案) 頂端的元件指示詞會以一致的順序放置。 重複的指示詞會依據命名空間或類型按字母順序放置,但有特殊第二層排序的@using指示詞除外。Blazor 範例應用程式和文件採用下列順序。 Blazor 專案範本所提供的元件可能會與下列順序不同,並使用不同的格式。 例如,Blazor 架構 Identity 元件在
@using指示詞區塊與@inject指示詞區塊之間包含空白行。 您可以在自己的應用程式中自由使用自訂排序配置和格式。文件和範例應用程式 Razor 指令順序:
@page-
@rendermode(.NET 8 或更新版本) @using-
System命名空間 (字母順序) -
Microsoft命名空間 (字母順序) - 第三方 API 命名空間 (字母順序)
- 應用程式命名空間 (字母順序)
-
- 其他指令 (字母順序)
注意
轉譯模式 只會套用在 Blazor Web App中,並包含與轉譯元件建立用戶互動的模式。 如需詳細資訊,請參閱 ASP.NET Core Blazor 轉譯模式。
指令之間不會出現空白行。 指示詞與 Razor 標記的第一行之間會出現一個空白行。
範例:
@page "/doctor-who-episodes/{season:int}" @rendermode InteractiveWebAssembly @using System.Globalization @using System.Text.Json @using Microsoft.AspNetCore.Localization @using Mandrill @using BlazorSample.Components.Layout @attribute [Authorize] @implements IAsyncDisposable @inject IJSRuntime JS @inject ILogger<DoctorWhoEpisodes> Logger <PageTitle>Doctor Who Episode List</PageTitle> ...指示詞屬性:會變更元件元素的整合或運作方式。
範例:
<input @bind="episodeId" />您可以在指令屬性值的前面加上 at 符號 (
@),適用於非明確表示式 (Razor),但我們不建議這麼做,文件中的範例也沒有採用這種做法。
本文和其他 Blazor 元件集文章會進一步說明元件中使用的指示詞和指示詞屬性。 如需 Razor 語法的一般資訊,請參閱 ASP.NET Core 的 Razor 語法參考。
元件名稱、類別名稱和命名空間
元件的名稱必須以大寫字元開頭:
支援:ProductDetail.razor
不支援:productDetail.razor
Blazor 文件中使用的通用 Blazor 命名慣例包括:
- 檔案路徑和檔案名稱會使用 Pascal 大小寫†並顯示在顯示程式碼範例之前。 如果路徑存在,則代表一般資料夾位置。 例如,
Components/Pages/ProductDetail.razor代表ProductDetail元件的檔案名稱為ProductDetail.razor,且位於應用程式的Pages資料夾的Components資料夾中。 - 可路由元件的檔案路徑會以其 URL 相符格式呈現,以小寫加上連字號(例如「kebab-case」),並在元件的路由範本中,單字之間以連字號取代空格。 例如,路由範本為
ProductDetail(/product-detail) 的@page "/product-detail"元件會在瀏覽器中於相對 URL/product-detail被請求。
†Pascal 命名法(大駝峰式命名法)是一種命名慣例,其特點是不含空格和標點符號,並且每個單字的第一個字母都大寫,包括第一個單字。
‡kebab 命名法是一種不含空格和標點符號的命名慣例,在字組之間使用小寫字母和連字號。
元件是一般的 C# 類別,而且可以放到專案內的任何位置。 產生網頁的元件通常位於 Components/Pages 資料夾中。 非網頁元件則經常放在 Components 資料夾中,或放在新增至專案的自訂資料夾中。
一般而言,元件的命名空間會衍生自應用程式的根命名空間,以及元件在應用程式內的位置 (資料夾)。 如果應用程式的根命名空間是 BlazorSample,而且 Counter 元件位於 Components/Pages 資料夾中:
-
Counter元件的命名空間為BlazorSample.Components.Pages。 - 元件的完整類型名稱為
BlazorSample.Components.Pages.Counter。
對於保有元件的自訂資料夾,請將 @using 指示詞新增至父元件或新增至應用程式的 _Imports.razor 檔案。 下列範例會讓 AdminComponents 資料夾中的元件變為可用狀態:
@using BlazorSample.AdminComponents
注意
@using 檔案中的 _Imports.razor 指示詞只會套用至 Razor 檔案 (.razor),而不會套用至 C# 檔案 (.cs)。
支援別名化的 using 陳述式。 在下列範例中,WeatherForecast 元件的公用 GridRendering 類別會以應用程式其他位置元件中的 WeatherForecast 形式提供:
@using WeatherForecast = Components.Pages.GridRendering.WeatherForecast
您也可以使用元件的完整名稱來參考元件,如此便不必使用 @using 指示詞。 下列範例會直接參考應用程式 ProductDetail 資料夾中的 AdminComponents/Pages 元件:
<BlazorSample.AdminComponents.Pages.ProductDetail />
使用 Razor 撰寫的元件,其命名空間會以下列項目作為基礎 (依優先順序列出):
-
@namespace檔案標記中的 Razor 指令(例如,@namespace BlazorSample.CustomNamespace)。 - 專案的
RootNamespace位於專案檔案中 (例如,<RootNamespace>BlazorSample</RootNamespace>)。 - 專案命名空間以及從專案根目錄到元件的路徑。 例如,架構會將專案命名空間為
{PROJECT NAMESPACE}/Components/Pages/Home.razor的BlazorSample解析為BlazorSample.Components.Pages元件的命名空間Home。{PROJECT NAMESPACE}是專案命名空間。 元件會遵循 C# 名稱繫結規則。 在此範例的Home元件中,範圍內的元件是所有元件:- 在相同資料夾中是
Components/Pages。 - 專案根目錄中未明確指定不同命名空間的元件。
- 在相同資料夾中是
不支援下列項目:
-
global::限定性條件。 - 部分限定名稱。 例如,您無法將
@using BlazorSample.Components新增至元件,然後使用NavMenu參考應用程式Components/Layout資料夾 (Components/Layout/NavMenu.razor) 中的<Layout.NavMenu></Layout.NavMenu>元件。
元件的名稱必須以大寫字元開頭:
支援:ProductDetail.razor
不支援:productDetail.razor
Blazor 文件中使用的通用 Blazor 命名慣例包括:
- 檔案路徑和檔案名稱會使用 Pascal 大小寫†並顯示在顯示程式碼範例之前。 如果路徑存在,則代表一般資料夾位置。 例如,
Pages/ProductDetail.razor代表ProductDetail元件的檔案名稱為ProductDetail.razor,且位於應用程式的Pages資料夾中。 - 可路由元件的檔案路徑會以其 URL 相符格式呈現,以小寫加上連字號(例如「kebab-case」),並在元件的路由範本中,單字之間以連字號取代空格。 例如,路由範本為
ProductDetail(/product-detail) 的@page "/product-detail"元件會在瀏覽器中於相對 URL/product-detail被請求。
†Pascal 命名法(大駝峰式命名法)是一種命名慣例,其特點是不含空格和標點符號,並且每個單字的第一個字母都大寫,包括第一個單字。
‡kebab 命名法是一種不含空格和標點符號的命名慣例,在字組之間使用小寫字母和連字號。
元件是一般的 C# 類別,而且可以放到專案內的任何位置。 產生網頁的元件通常位於 Pages 資料夾中。 非網頁元件則經常放在 Shared 資料夾中,或放在新增至專案的自訂資料夾中。
一般而言,元件的命名空間會衍生自應用程式的根命名空間,以及元件在應用程式內的位置 (資料夾)。 如果應用程式的根命名空間是 BlazorSample,而且 Counter 元件位於 Pages 資料夾中:
-
Counter元件的命名空間為BlazorSample.Pages。 - 元件的完整類型名稱為
BlazorSample.Pages.Counter。
對於保有元件的自訂資料夾,請將 @using 指示詞新增至父元件或新增至應用程式的 _Imports.razor 檔案。 下列範例會讓 AdminComponents 資料夾中的元件變為可用狀態:
@using BlazorSample.AdminComponents
注意
@using 檔案中的 _Imports.razor 指示詞只會套用至 Razor 檔案 (.razor),而不會套用至 C# 檔案 (.cs)。
支援別名化的 using 陳述式。 在下列範例中,WeatherForecast 元件的公用 GridRendering 類別會以應用程式其他位置元件中的 WeatherForecast 形式提供:
@using WeatherForecast = Pages.GridRendering.WeatherForecast
您也可以使用元件的完整名稱來參考元件,如此便不必使用 @using 指示詞。 下列範例會直接參考應用程式 ProductDetail 資料夾中的 Components 元件:
<BlazorSample.Components.ProductDetail />
使用 Razor 撰寫的元件,其命名空間會以下列項目作為基礎 (依優先順序列出):
-
@namespace檔案標記中的 Razor 指令(例如,@namespace BlazorSample.CustomNamespace)。 - 專案的
RootNamespace位於專案檔案中 (例如,<RootNamespace>BlazorSample</RootNamespace>)。 - 專案命名空間以及從專案根目錄到元件的路徑。 例如,架構會將專案命名空間為
{PROJECT NAMESPACE}/Pages/Index.razor的BlazorSample解析為BlazorSample.Pages元件的命名空間Index。{PROJECT NAMESPACE}是專案命名空間。 元件會遵循 C# 名稱繫結規則。 在此範例的Index元件中,範圍內的元件是所有元件:- 在相同資料夾中是
Pages。 - 專案根目錄中未明確指定不同命名空間的元件。
- 在相同資料夾中是
不支援下列項目:
-
global::限定性條件。 - 部分限定名稱。 例如,您無法將
@using BlazorSample新增至元件,然後使用NavMenu參考應用程式Shared資料夾 (Shared/NavMenu.razor) 中的<Shared.NavMenu></Shared.NavMenu>元件。
部分類別支援
元件會以 C# 部分類別的形式產生,並使用下列任一方法來撰寫:
- 單一檔案包含一或多個
@code區塊、HTML 標記和 Razor 標記中所定義的 C# 程式碼。 Blazor 專案範本會使用此單一檔案方法來定義其元件。 - HTML 和 Razor 標記會放在 Razor 檔案 (
.razor) 中。 C# 程式碼會放在定義為部分類別的程式碼後置檔案 (.cs) 中。
注意
定義元件特定樣式的元件樣式表是不同的檔案 (.css)。
BlazorCSS 隔離稍後會在 ASP.NET CORE Blazor CSS 隔離中說明。
下列範例會顯示從 Counter 專案範本產生的應用程式中,所具有的預設 @code 元件與 Blazor 區塊。 標記和 C# 程式碼位於相同檔案中。 這是在撰寫元件時最常採用的方法。
Counter.razor:
@page "/counter"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount() => currentCount++;
}
@page "/counter"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount() => currentCount++;
}
@page "/counter"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
@page "/counter"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
@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++;
}
}
@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++;
}
}
下列 Counter 元件會將呈現 HTML 和 Razor 標記從 C# 程式碼中分割,並使用具有部分類別的程式碼後置檔案。 一些組織和開發人員偏好將標記與 C# 程式碼分割,以組織其元件程式碼,符合他們偏好的運作方式。 例如,組織的 UI 專家可以獨立處理展示層,而另一位開發人員則可以專注於元件的 C# 邏輯。 使用自動產生的程式碼或來源產生器時,此方法也很有用。 如需詳細資訊,請參閱部分類別和方法 (C# 程式設計手冊)。
CounterPartialClass.razor:
@page "/counter-partial-class"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
CounterPartialClass.razor.cs:
namespace BlazorSample.Components.Pages;
public partial class CounterPartialClass
{
private int currentCount = 0;
private void IncrementCount() => currentCount++;
}
namespace BlazorSample.Components.Pages;
public partial class CounterPartialClass
{
private int currentCount = 0;
private void IncrementCount() => currentCount++;
}
namespace BlazorSample.Pages;
public partial class CounterPartialClass
{
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
namespace BlazorSample.Pages
{
public partial class CounterPartialClass
{
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
}
@using 檔案中的 _Imports.razor 指示詞只會套用至 Razor 檔案 (.razor),而不會套用至 C# 檔案 (.cs)。 請視需要將命名空間新增至部分類別檔案。
元件所使用的典型命名空間:
using System.Net.Http;
using System.Net.Http.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Sections
using Microsoft.AspNetCore.Components.Web;
using static Microsoft.AspNetCore.Components.Web.RenderMode;
using Microsoft.AspNetCore.Components.Web.Virtualization;
using Microsoft.JSInterop;
典型命名空間也包含應用程式的命名空間,以及對應至應用程式 Components 資料夾的命名空間:
using BlazorSample;
using BlazorSample.Components;
也可以包含其他資料夾,例如 Layout 資料夾:
using BlazorSample.Components.Layout;
using System.Net.Http;
using System.Net.Http.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.Web.Virtualization;
using Microsoft.JSInterop;
典型命名空間也包含應用程式的命名空間,以及對應至應用程式 Shared 資料夾的命名空間:
using BlazorSample;
using BlazorSample.Shared;
using System.Net.Http;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.JSInterop;
典型命名空間也包含應用程式的命名空間,以及對應至應用程式 Shared 資料夾的命名空間:
using BlazorSample;
using BlazorSample.Shared;
指定基底類別
@inherits 指示詞可用來指定元件的基底類別。 不同於使用只從 C# 邏輯分割標記的部分類別,使用基底類別可讓您繼承 C# 程式碼,以便跨共用基底類別屬性和方法的元件群組使用。 使用基底類別可減少應用程式中的程式碼備援,且在將基底類別程式碼從類別庫提供給多個應用程式時很有用。 如需詳細資訊,請參閱在 C# 和 .NET 中繼承。
在下列範例中,BlazorRocksBase1 基底類別衍生自 ComponentBase。
BlazorRocks1.razor:
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1
<PageTitle>Blazor Rocks!</PageTitle>
<h1>Blazor Rocks! Example 1</h1>
<p>
@BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1
<PageTitle>Blazor Rocks!</PageTitle>
<h1>Blazor Rocks! Example 1</h1>
<p>
@BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1
<PageTitle>Blazor Rocks!</PageTitle>
<h1>Blazor Rocks! Example 1</h1>
<p>
@BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1
<PageTitle>Blazor Rocks!</PageTitle>
<h1>Blazor Rocks! Example 1</h1>
<p>
@BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1
<h1>Blazor Rocks! Example 1</h1>
<p>
@BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1
<h1>Blazor Rocks! Example 1</h1>
<p>
@BlazorRocksText
</p>
BlazorRocksBase1.cs:
using Microsoft.AspNetCore.Components;
namespace BlazorSample;
public class BlazorRocksBase1 : ComponentBase
{
public string BlazorRocksText { get; set; } = "Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;
namespace BlazorSample;
public class BlazorRocksBase1 : ComponentBase
{
public string BlazorRocksText { get; set; } = "Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;
namespace BlazorSample;
public class BlazorRocksBase1 : ComponentBase
{
public string BlazorRocksText { get; set; } =
"Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;
namespace BlazorSample;
public class BlazorRocksBase1 : ComponentBase
{
public string BlazorRocksText { get; set; } =
"Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;
namespace BlazorSample;
public class BlazorRocksBase1 : ComponentBase
{
public string BlazorRocksText { get; set; } =
"Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;
namespace BlazorSample;
public class BlazorRocksBase1 : ComponentBase
{
public string BlazorRocksText { get; set; } =
"Blazor rocks the browser!";
}
路由
在 Blazor 中實現路由功能的方法是,使用 @page 指示詞向應用程式中的每個可存取元件提供路由範本。 在編譯具有 Razor 指示詞的 @page 檔案時,所產生的類別會獲得 RouteAttribute 以指定路由範本。 在執行階段,路由器會搜尋具有 RouteAttribute 的元件類別,並轉譯其路由範本符合所要求 URL 的任何元件。
下列 HelloWorld 元件會使用 /hello-world 的路由範本,且元件的轉譯網頁會到達相對 URL /hello-world。
HelloWorld.razor:
@page "/hello-world"
<PageTitle>Hello World!</PageTitle>
<h1>Hello World!</h1>
@page "/hello-world"
<PageTitle>Hello World!</PageTitle>
<h1>Hello World!</h1>
@page "/hello-world"
<h1>Hello World!</h1>
@page "/hello-world"
<h1>Hello World!</h1>
@page "/hello-world"
<h1>Hello World!</h1>
@page "/hello-world"
<h1>Hello World!</h1>
不論您是否有將元件新增至應用程式的 UI 導覽,上述元件都會透過瀏覽器在 /hello-world 中載入。 您也可以選擇將元件新增至 NavMenu 元件,讓後者的連結出現在應用程式的 UI 型導覽中。
針對上述 HelloWorld 元件,您可以將 NavLink 元件新增至 NavMenu 元件。 如需詳細資訊,包括 NavLink 和 NavMenu 元件的描述,請參閱 ASP.NET Core Blazor 路由和導覽。
標記語言 (if referring to document/markup language), 加價 (if referring to price markup)
元件的 UI 會使用 Razor 語法來定義,此語法由 Razor 標記、C# 和 HTML 組成。 在編譯應用程式時,HTML 標記和 C# 轉譯邏輯會轉換為元件類別。 所產生的類別名稱與檔案的名稱相符。
元件類別的成員會定義於一或多個 @code 區塊中。 在 @code 區塊中,系統會使用 C# 來指定和處理元件狀態:
- 屬性和欄位的初始設定式。
- 父元件和路由參數所傳遞引數中的參數值。
- 使用者事件處理、生命週期事件和自訂元件邏輯的方法。
使用開頭為 @ 符號的 C# 運算式即可在轉譯邏輯中使用元件成員。 例如,藉由在欄位名稱前面加上 @ 即可轉譯 C# 欄位。 下列 Markup 元件會評估和轉譯:
-
headingFontStyle,以取得標題元素的 CSS 屬性值font-style。 -
headingText,以取得標題元素的內容。
Markup.razor:
@page "/markup"
<PageTitle>Markup</PageTitle>
<h1>Markup Example</h1>
<h2 style="font-style:@headingFontStyle">@headingText</h2>
@code {
private string headingFontStyle = "italic";
private string headingText = "Put on your new Blazor!";
}
@page "/markup"
<PageTitle>Markup</PageTitle>
<h1>Markup Example</h1>
<h2 style="font-style:@headingFontStyle">@headingText</h2>
@code {
private string headingFontStyle = "italic";
private string headingText = "Put on your new Blazor!";
}
@page "/markup"
<h1 style="font-style:@headingFontStyle">@headingText</h1>
@code {
private string headingFontStyle = "italic";
private string headingText = "Put on your new Blazor!";
}
@page "/markup"
<h1 style="font-style:@headingFontStyle">@headingText</h1>
@code {
private string headingFontStyle = "italic";
private string headingText = "Put on your new Blazor!";
}
@page "/markup"
<h1 style="font-style:@headingFontStyle">@headingText</h1>
@code {
private string headingFontStyle = "italic";
private string headingText = "Put on your new Blazor!";
}
@page "/markup"
<h1 style="font-style:@headingFontStyle">@headingText</h1>
@code {
private string headingFontStyle = "italic";
private string headingText = "Put on your new Blazor!";
}
注意
整個 Blazor 文件中的範例會為私人成員指定 private 存取修飾符號。 私有成員的作用域僅限於元件的類別中。 不過,如果沒有任何存取修飾詞存在,C# 則會採用 private 存取修飾詞,因此您可以選擇是否要在自己的程式碼中將成員明確標記為「private」。 如需存取修飾詞的詳細資訊,請參閱 存取修飾詞 (C# 程式設計指南)。
Blazor 架構會在內部以轉譯樹狀結構 (由元件的 DOM 和階層式樣式表物件模型 (CSSOM) 組合而成) 的形式處理元件。 初次轉譯元件之後,便會重新產生元件的轉譯樹狀結構以回應事件。 Blazor 會拿新的轉譯樹狀結構與上一個轉譯樹狀結構做比較,並將任何修改套用至瀏覽器的 DOM 以供顯示。 如需詳細資訊,請參閱 ASP.NET Core Razor 元件轉譯。
C# 控制項結構、指示詞和指示詞屬性的 Razor 語法採用小寫 (範例:@if、@code、@bind)。 屬性名稱大寫 (範例:@Body 的 LayoutComponentBase.Body)。
非同步方法 (async) 不支援傳回 void
Blazor 架構不會追蹤 void 傳回的非同步方法 (async)。 因此,如果例外狀況未被捕捉,且void被傳回,整個進程就會失敗。 總是從異步方法傳回 Task/ValueTask 。
巢狀元件
元件可以使用 HTML 語法宣告,以包含其他元件。 使用元件的標記看起來像是 HTML 標籤,其中標籤名稱是元件類型。
請看一下下列 Heading 元件,其可供其他元件使用以顯示標題。
Heading.razor:
<h1 style="font-style:@headingFontStyle">Heading Example</h1>
@code {
private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>
@code {
private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>
@code {
private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>
@code {
private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>
@code {
private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>
@code {
private string headingFontStyle = "italic";
}
HeadingExample 元件中的下列標記會在 Heading 標籤出現的位置轉譯上述 <Heading /> 元件。
HeadingExample.razor:
@page "/heading-example"
<PageTitle>Heading</PageTitle>
<h1>Heading Example</h1>
<Heading />
@page "/heading-example"
<PageTitle>Heading</PageTitle>
<h1>Heading Example</h1>
<Heading />
@page "/heading-example"
<Heading />
@page "/heading-example"
<Heading />
@page "/heading-example"
<Heading />
@page "/heading-example"
<Heading />
如果元件包含的 HTML 元素,其大寫的第一個字母與相同命名空間內的元件名稱不符,就會發出警告,指出該元素的名稱不符預期。 為元件的命名空間新增 @using 指示詞會讓元件變為可用狀態,如此便能解決警告。 如需詳細資訊,請參閱元件名稱、類別名稱和命名空間一節。
本節所示的 Heading 元件範例沒有 @page 指示詞,因此使用者無法透過在瀏覽器中直接要求來直接存取 Heading 元件。 不過,任何具有 @page 指示詞的元件都可以巢狀化到另一個元件中。 如果透過在 Heading 檔案頂端包含 @page "/heading" 而能夠直接存取 Razor 元件,則位於 /heading 和 /heading-example 的瀏覽器要求都會轉譯元件。
元件參數
「元件參數」會將資料傳遞至元件,其定義方式則是在元件類別上使用公用的 C# 屬性與 [Parameter] 屬性。
在下列 ParameterChild 元件中,元件參數包括:
內建參考型別。
-
System.String 在
Title中傳遞標題。 -
System.Int32 在
Count中傳遞計數。
-
System.String 在
使用者自定義的參考類型 (
PanelBody),用於在Body中傳遞 Bootstrap 卡片主體。PanelBody.cs:namespace BlazorSample; public class PanelBody { public string? Text { get; set; } public string? Style { get; set; } }namespace BlazorSample; public class PanelBody { public string? Text { get; set; } public string? Style { get; set; } }public class PanelBody { public string? Text { get; set; } public string? Style { get; set; } }public class PanelBody { public string? Text { get; set; } public string? Style { get; set; } }public class PanelBody { public string Text { get; set; } public string Style { get; set; } }public class PanelBody { public string Text { get; set; } public string Style { get; set; } }
ParameterChild.razor:
<div class="card w-25" style="margin-bottom:15px">
<div class="card-header font-weight-bold">@Title</div>
<div class="card-body" style="font-style:@Body.Style">
<p>@Body.Text</p>
@if (Count is not null)
{
<p>The count is @Count.</p>
}
</div>
</div>
@code {
[Parameter]
public string Title { get; set; } = "Set By Child";
[Parameter]
public PanelBody Body { get; set; } =
new()
{
Text = "Card content set by child.",
Style = "normal"
};
[Parameter]
public int? Count { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
<div class="card-header font-weight-bold">@Title</div>
<div class="card-body" style="font-style:@Body.Style">
<p>@Body.Text</p>
@if (Count is not null)
{
<p>The count is @Count.</p>
}
</div>
</div>
@code {
[Parameter]
public string Title { get; set; } = "Set By Child";
[Parameter]
public PanelBody Body { get; set; } =
new()
{
Text = "Card content set by child.",
Style = "normal"
};
[Parameter]
public int? Count { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
<div class="card-header font-weight-bold">@Title</div>
<div class="card-body" style="font-style:@Body.Style">
<p>@Body.Text</p>
@if (Count is not null)
{
<p>The count is @Count.</p>
}
</div>
</div>
@code {
[Parameter]
public string Title { get; set; } = "Set By Child";
[Parameter]
public PanelBody Body { get; set; } =
new()
{
Text = "Set by child.",
Style = "normal"
};
[Parameter]
public int? Count { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
<div class="card-header font-weight-bold">@Title</div>
<div class="card-body" style="font-style:@Body.Style">
<p>@Body.Text</p>
@if (Count is not null)
{
<p>The count is @Count.</p>
}
</div>
</div>
@code {
[Parameter]
public string Title { get; set; } = "Set By Child";
[Parameter]
public PanelBody Body { get; set; } =
new()
{
Text = "Set by child.",
Style = "normal"
};
[Parameter]
public int? Count { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
<div class="card-header font-weight-bold">@Title</div>
<div class="card-body" style="font-style:@Body.Style">
<p>@Body.Text</p>
@if (Count is not null)
{
<p>The count is @Count.</p>
}
</div>
</div>
@code {
[Parameter]
public string Title { get; set; } = "Set By Child";
[Parameter]
public PanelBody Body { get; set; } =
new()
{
Text = "Set by child.",
Style = "normal"
};
[Parameter]
public int? Count { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
<div class="card-header font-weight-bold">@Title</div>
<div class="card-body" style="font-style:@Body.Style">
<p>@Body.Text</p>
@if (Count is not null)
{
<p>The count is @Count.</p>
}
</div>
</div>
@code {
[Parameter]
public string Title { get; set; } = "Set By Child";
[Parameter]
public PanelBody Body { get; set; } =
new PanelBody()
{
Text = "Set by child.",
Style = "normal"
};
[Parameter]
public int? Count { get; set; }
}
警告
支援為元件參數提供初始值,但請勿在第一次渲染元件之後,建立會寫入到其自身參數的元件。 如需詳細資訊,請參閱避免在 ASP.NET Core 中覆寫參數Blazor。
ParameterChild 元件的元件參數可以透過 HTML 標籤的自變數來設定,以轉譯 ParameterChild 元件的實例。 下列父元件會轉譯兩個 ParameterChild 元件:
- 第一個
ParameterChild元件在轉譯時不會提供參數引數。 - 第二個
ParameterChild元件會從父元件接收Title和Body的值,該元件會使用 明確的 C# 運算式 來設定PanelBody屬性的值。
Parameter1.razor:
@page "/parameter-1"
<PageTitle>Parameter 1</PageTitle>
<h1>Parameter Example 1</h1>
<h1>Child component (without attribute values)</h1>
<ParameterChild />
<h1>Child component (with attribute values)</h1>
<ParameterChild Title="Set by Parent"
Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />
Parameter1.razor:
@page "/parameter-1"
<PageTitle>Parameter 1</PageTitle>
<h1>Parameter Example 1</h1>
<h1>Child component (without attribute values)</h1>
<ParameterChild />
<h1>Child component (with attribute values)</h1>
<ParameterChild Title="Set by Parent"
Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />
ParameterParent.razor:
@page "/parameter-parent"
<h1>Child component (without attribute values)</h1>
<ParameterChild />
<h1>Child component (with attribute values)</h1>
<ParameterChild Title="Set by Parent"
Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />
ParameterParent.razor:
@page "/parameter-parent"
<h1>Child component (without attribute values)</h1>
<ParameterChild />
<h1>Child component (with attribute values)</h1>
<ParameterChild Title="Set by Parent"
Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />
ParameterParent.razor:
@page "/parameter-parent"
<h1>Child component (without attribute values)</h1>
<ParameterChild />
<h1>Child component (with attribute values)</h1>
<ParameterChild Title="Set by Parent"
Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />
ParameterParent.razor:
@page "/parameter-parent"
<h1>Child component (without attribute values)</h1>
<ParameterChild />
<h1>Child component (with attribute values)</h1>
<ParameterChild Title="Set by Parent"
Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />
當父元件未提供元件參數值時,下列從父元件轉譯的 HTML 標記會顯示 ParameterChild 元件預設值。 當父元件提供元件參數值時,它們會取代 ParameterChild 元件的預設值。
注意
為了清楚起見,大部分轉譯的 CSS 樣式類別和某些元素不會顯示在下列轉譯的 HTML 標記中。 下列範例所示範的主要概念是,父元件會使用其元件參數,將值指派給子元件。
<h1>Child component (without attribute values)</h1>
<div>Set By Child</div>
<div style="font-style:normal">
<p>Card content set by child.</p>
</div>
<h1>Child component (with attribute values)</h1>
<div>Set by Parent</div>
<div style="font-style:italic">
<p>Set by parent.</p>
</div>
將方法的 C# 欄位、屬性或結果指派給元件參數來做為 HTML 屬性值。 屬性的值通常可以是符合參數類型的任何 C# 運算式。 屬性的值可以選擇性地以 Razor 保留 @ 符號前置,但並非必要。
如果元件參數的類型為字串,則會改將屬性值視為 C# 字串常值。 如果您想要改為指定 C# 運算式,請使用 @ 前置詞。
下列父元件會顯示上述 ParameterChild 元件的四個實例,並將其 Title 參數值設定為:
-
title欄位的值。 -
GetTitleC# 方法的結果。 - 當前本機日期以完整格式顯示,使用 ToLongDateString 並運用隱含的 C# 運算式。
-
panelData物件的Title屬性。
第五個 ParameterChild 元件實例也會設定 Count 參數。 請注意,string型別的參數需要 @ 前置詞,以確保不將表達式視為字串文字。 不過,Count 是可為 Null 的整數(System.Int32),因此 Count 可以接收沒有 count 前綴的 @ 值。 您可以制定替代程式碼慣例,要求組織中的開發人員一律使用 @前綴。 無論如何,我們只建議您在 Razor 標記中採用一致的方法來傳遞元件參數。
根據 HTML5 的規格,在大部分情況下,您可以選擇是否在參數屬性值外加上引號。 例如,Value=this 會受到支援,Value="this" 則不會。 不過,我們還是建議使用引號,因為這麼做不僅方便記住,也廣為 Web 型技術所採用。
在整個文件中,程式碼範例:
- 一律使用引號。 範例:
Value="this". - 除非必要,請勿對非字面值使用
@前置詞。 範例:Count="count",其中count是數字類型的變數。Count="@count"是有效的文體方法,但文件和範例不會採用慣例。 - 總是避免將
@用於常值,而不是在 Razor 運算式中。 範例:IsFixed="true". 這包括關鍵字 (例如this) 和null,但您可以視需要選擇加以使用。 例如,IsFixed="@true"雖不常見,但仍受到支援。
Parameter2.razor:
@page "/parameter-2"
<PageTitle>Parameter 2</PageTitle>
<h1>Parameter Example 2</h1>
<ParameterChild Title="@title" />
<ParameterChild Title="@GetTitle()" />
<ParameterChild Title="@DateTime.Now.ToLongDateString()" />
<ParameterChild Title="@panelData.Title" />
<ParameterChild Title="String literal title" Count="count" />
@code {
private string title = "From Parent field";
private PanelData panelData = new();
private int count = 12345;
private string GetTitle() => "From Parent method";
private class PanelData
{
public string Title { get; set; } = "From Parent object";
}
}
Parameter2.razor:
@page "/parameter-2"
<PageTitle>Parameter 2</PageTitle>
<h1>Parameter Example 2</h1>
<ParameterChild Title="@title" />
<ParameterChild Title="@GetTitle()" />
<ParameterChild Title="@DateTime.Now.ToLongDateString()" />
<ParameterChild Title="@panelData.Title" />
<ParameterChild Title="String literal title" Count="count" />
@code {
private string title = "From Parent field";
private PanelData panelData = new();
private int count = 12345;
private string GetTitle() => "From Parent method";
private class PanelData
{
public string Title { get; set; } = "From Parent object";
}
}
ParameterParent2.razor:
@page "/parameter-parent-2"
<ParameterChild Title="@title" />
<ParameterChild Title="@GetTitle()" />
<ParameterChild Title="@DateTime.Now.ToLongDateString()" />
<ParameterChild Title="@panelData.Title" />
<ParameterChild Title="String literal title" Count="count" />
@code {
private string title = "From Parent field";
private PanelData panelData = new();
private int count = 12345;
private string GetTitle()
{
return "From Parent method";
}
private class PanelData
{
public string Title { get; set; } = "From Parent object";
}
}
ParameterParent2.razor:
@page "/parameter-parent-2"
<ParameterChild Title="@title" />
<ParameterChild Title="@GetTitle()" />
<ParameterChild Title="@DateTime.Now.ToLongDateString()" />
<ParameterChild Title="@panelData.Title" />
<ParameterChild Title="String literal title" Count="count" />
@code {
private string title = "From Parent field";
private PanelData panelData = new();
private int count = 12345;
private string GetTitle()
{
return "From Parent method";
}
private class PanelData
{
public string Title { get; set; } = "From Parent object";
}
}
ParameterParent2.razor:
@page "/parameter-parent-2"
<ParameterChild Title="@title" />
<ParameterChild Title="@GetTitle()" />
<ParameterChild Title="@DateTime.Now.ToLongDateString()" />
<ParameterChild Title="@panelData.Title" />
<ParameterChild Title="String literal title" Count="count" />
@code {
private string title = "From Parent field";
private PanelData panelData = new PanelData();
private int count = 12345;
private string GetTitle()
{
return "From Parent method";
}
private class PanelData
{
public string Title { get; set; } = "From Parent object";
}
}
注意
將 C# 成員指派給元件參數時,請勿在參數的 HTML 屬性前面加上 @。
正確 (Title 是字串參數,Count 是數字類型參數):
<ParameterChild Title="@title" Count="count" />
<ParameterChild Title="@title" Count="@count" />
不正確:
<ParameterChild @Title="@title" @Count="count" />
<ParameterChild @Title="@title" @Count="@count" />
和在 Razor 頁面 (.cshtml) 中不同,Blazor 無法在轉譯元件時於 Razor 運算式中執行非同步工作。 這是因為 Blazor 的設計目的是轉譯互動式 UI。 在互動式 UI 中,畫面一定要顯示內容,因此封鎖轉譯流程並不合理。 相反地,非同步工作會在其中一個非同步生命週期事件期間執行。 在每個非同步生命週期事件過後,元件可能會重新轉譯。 下列 Razor 語法不受支援:
<ParameterChild Title="await ..." />
<ParameterChild Title="@await ..." />
上述範例中的程式碼會在建置應用程式時產生「編譯器錯誤」:
「await」運算子只能用於非同步方法。 請考慮使用「async」修飾詞標記這個方法,並將其傳回類型變更為「Task」。
若要以非同步方式取得上述範例中 Title 參數的值,元件可以使用 OnInitializedAsync 生命週期事件,如下列範例所示:
<ParameterChild Title="@title" />
@code {
private string? title;
protected override async Task OnInitializedAsync()
{
title = await ...;
}
}
如需詳細資訊,請參閱 ASP.NET Core Razor 元件生命週期。
不支援使用明確的Razor運算式來串接文字與運算式結果以指派給參數。 下列範例會試圖將文字「Set by 」與物件的屬性值串連起來。 雖然Razor 頁面 (.cshtml) 支援此語法,但要指派到元件中的子項目的 Title 參數時,則會無效。 下列 Razor 語法不受支援:
<ParameterChild Title="Set by @(panelData.Title)" />
上述範例中的程式碼會在建置應用程式時產生「編譯器錯誤」:
元件屬性 (attribute) 不支援複雜內容 (混合 C# 和標記)。
若要支援指派組合值,請使用方法、欄位或屬性。 下列範例會在 C# 方法 Set by 中執行「GetTitle」和物件屬性 (property) 值的串連:
Parameter3.razor:
@page "/parameter-3"
<PageTitle>Parameter 3</PageTitle>
<h1>Parameter Example 3</h1>
<ParameterChild Title="@GetTitle()" />
@code {
private PanelData panelData = new();
private string GetTitle() => $"Set by {panelData.Title}";
private class PanelData
{
public string Title { get; set; } = "Parent";
}
}
Parameter3.razor:
@page "/parameter-3"
<PageTitle>Parameter 3</PageTitle>
<h1>Parameter Example 3</h1>
<ParameterChild Title="@GetTitle()" />
@code {
private PanelData panelData = new();
private string GetTitle() => $"Set by {panelData.Title}";
private class PanelData
{
public string Title { get; set; } = "Parent";
}
}
ParameterParent3.razor:
@page "/parameter-parent-3"
<ParameterChild Title="@GetTitle()" />
@code {
private PanelData panelData = new();
private string GetTitle() => $"Set by {panelData.Title}";
private class PanelData
{
public string Title { get; set; } = "Parent";
}
}
ParameterParent3.razor:
@page "/parameter-parent-3"
<ParameterChild Title="@GetTitle()" />
@code {
private PanelData panelData = new();
private string GetTitle() => $"Set by {panelData.Title}";
private class PanelData
{
public string Title { get; set; } = "Parent";
}
}
ParameterParent3.razor:
@page "/parameter-parent-3"
<ParameterChild Title="@GetTitle()" />
@code {
private PanelData panelData = new();
private string GetTitle() => $"Set by {panelData.Title}";
private class PanelData
{
public string Title { get; set; } = "Parent";
}
}
ParameterParent3.razor:
@page "/parameter-parent-3"
<ParameterChild Title="@GetTitle()" />
@code {
private PanelData panelData = new PanelData();
private string GetTitle() => $"Set by {panelData.Title}";
private class PanelData
{
public string Title { get; set; } = "Parent";
}
}
如需詳細資訊,請參閱 ASP.NET Core 的 Razor 語法參考。
警告
支援為元件參數提供初始值,但請勿在第一次渲染元件之後,建立會寫入到其自身參數的元件。 如需詳細資訊,請參閱避免在 ASP.NET Core 中覆寫參數Blazor。
元件參數應該宣告為自動實作的屬性(auto 屬性),這表示它們不應該在其 或 get 存取子中包含set自定義邏輯。 例如,下列 StartData 屬性是 auto 屬性:
[Parameter]
public DateTime StartData { get; set; }
請勿將自訂邏輯放在 get 或 set 存取子中,因為元件參數純粹是作為父元件用來將資訊流向子元件的通道而已。 如果子元件屬性的 set 存取子包含的邏輯會導致父元件重新轉譯,則會產生無限循環的轉譯。 其他副作用包括非預期的額外轉譯和參數值覆寫。
若要轉換所接收的參數值:
- 讓參數屬性仍作為自動屬性,以代表所提供的未經處理資料。
- 建立不同的屬性或方法,以根據參數屬性提供經過轉換的資料。
覆寫 OnParametersSetAsync 以在每次收到新資料時轉換所接收的參數。
支援在元件參數中寫入初始值,因為指派初始值並不會干擾 Blazor 自動轉譯元件。 在元件中,將目前的本機 DateTime 與 DateTime.Now 指派給 StartData 屬於有效的語法:
[Parameter]
public DateTime StartData { get; set; } = DateTime.Now;
在初始指派 DateTime.Now 之後,請勿在開發人員程式碼的 StartData 中指派值。 如需詳細資訊,請參閱避免在 ASP.NET Core 中覆寫參數Blazor。
套用 [EditorRequired] 屬性以指定必要的元件參數。 如果未提供參數值,編輯器或建置工具可能會向使用者顯示警告。 這個屬性只有在也標記了[Parameter]屬性的屬性上才有效。 在設計階段以及在建置應用程式時,會強制執行 EditorRequiredAttribute。 屬性 (attribute) 不會在執行階段強制執行,而且也不會保證非 null 參數值。
[Parameter]
[EditorRequired]
public string? Title { get; set; }
也支援單行屬性清單:
[Parameter, EditorRequired]
public string? Title { get; set; }
請勿在元件參數屬性上使用 required 修飾詞或 init 存取子。 元件通常會使用反映來具現化和指派參數值,這會略過 init 和 required 旨在提供的保證。 請改用 [EditorRequired] 屬性以指定必要的元件參數。
請勿在元件參數屬性上使用 init 存取子,因為透過 ParameterView.SetParameterProperties 的反射機制設定元件參數值,會略過僅限 init 的 setter 限制。 使用 [EditorRequired] 屬性以指定必要的元件參數。
請勿在元件參數屬性上使用 init 存取子,因為透過 ParameterView.SetParameterProperties 的反射機制設定元件參數值,會略過僅限 init 的 setter 限制。
Tuples (API 文件) 支援用於元件參數和 RenderFragment 類型。 下列元件參數範例會在 Tuple 中傳遞三個值:
RenderTupleChild.razor:
<div class="card w-50" style="margin-bottom:15px">
<div class="card-header font-weight-bold">Tuple Card</div>
<div class="card-body">
<ul>
<li>Integer: @Data?.Item1</li>
<li>String: @Data?.Item2</li>
<li>Boolean: @Data?.Item3</li>
</ul>
</div>
</div>
@code {
[Parameter]
public (int, string, bool)? Data { get; set; }
}
RenderTupleParent.razor:
@page "/render-tuple-parent"
<PageTitle>Render Tuple Parent</PageTitle>
<h1>Render Tuple Parent Example</h1>
<RenderTupleChild Data="data" />
@code {
private (int, string, bool) data = new(999, "I aim to misbehave.", true);
}
支援具名元組,如以下範例所示:
NamedTupleChild.razor:
<div class="card w-50" style="margin-bottom:15px">
<div class="card-header font-weight-bold">Tuple Card</div>
<div class="card-body">
<ul>
<li>Integer: @Data?.TheInteger</li>
<li>String: @Data?.TheString</li>
<li>Boolean: @Data?.TheBoolean</li>
</ul>
</div>
</div>
@code {
[Parameter]
public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; }
}
NamedTuples.razor:
@page "/named-tuples"
<PageTitle>Named Tuples</PageTitle>
<h1>Named Tuples Example</h1>
<NamedTupleChild Data="data" />
@code {
private (int TheInteger, string TheString, bool TheBoolean) data =
new(999, "I aim to misbehave.", true);
}
引用 ©2005 Universal Pictures: Serenity (Nathan Fillion)
Tuples (API 文件) 支援用於元件參數和 RenderFragment 類型。 下列元件參數範例會在 Tuple 中傳遞三個值:
RenderTupleChild.razor:
<div class="card w-50" style="margin-bottom:15px">
<div class="card-header font-weight-bold">Tuple Card</div>
<div class="card-body">
<ul>
<li>Integer: @Data?.Item1</li>
<li>String: @Data?.Item2</li>
<li>Boolean: @Data?.Item3</li>
</ul>
</div>
</div>
@code {
[Parameter]
public (int, string, bool)? Data { get; set; }
}
RenderTupleParent.razor:
@page "/render-tuple-parent"
<PageTitle>Render Tuple Parent</PageTitle>
<h1>Render Tuple Parent Example</h1>
<RenderTupleChild Data="data" />
@code {
private (int, string, bool) data = new(999, "I aim to misbehave.", true);
}
支援具名元組,如以下範例所示:
NamedTupleChild.razor:
<div class="card w-50" style="margin-bottom:15px">
<div class="card-header font-weight-bold">Tuple Card</div>
<div class="card-body">
<ul>
<li>Integer: @Data?.TheInteger</li>
<li>String: @Data?.TheString</li>
<li>Boolean: @Data?.TheBoolean</li>
</ul>
</div>
</div>
@code {
[Parameter]
public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; }
}
NamedTuples.razor:
@page "/named-tuples"
<PageTitle>Named Tuples</PageTitle>
<h1>Named Tuples Example</h1>
<NamedTupleChild Data="data" />
@code {
private (int TheInteger, string TheString, bool TheBoolean) data =
new(999, "I aim to misbehave.", true);
}
引用 ©2005 Universal Pictures: Serenity (Nathan Fillion)
Tuples (API 文件) 支援用於元件參數和 RenderFragment 類型。 下列元件參數範例會在 Tuple 中傳遞三個值:
RenderTupleChild.razor:
<div class="card w-50" style="margin-bottom:15px">
<div class="card-header font-weight-bold"><code>Tuple</code> Card</div>
<div class="card-body">
<ul>
<li>Integer: @Data?.Item1</li>
<li>String: @Data?.Item2</li>
<li>Boolean: @Data?.Item3</li>
</ul>
</div>
</div>
@code {
[Parameter]
public (int, string, bool)? Data { get; set; }
}
RenderTupleParent.razor:
@page "/render-tuple-parent"
<h1>Render Tuple Parent</h1>
<RenderTupleChild Data="data" />
@code {
private (int, string, bool) data = new(999, "I aim to misbehave.", true);
}
支援具名元組,如以下範例所示:
RenderNamedTupleChild.razor:
<div class="card w-50" style="margin-bottom:15px">
<div class="card-header font-weight-bold"><code>Tuple</code> Card</div>
<div class="card-body">
<ul>
<li>Integer: @Data?.TheInteger</li>
<li>String: @Data?.TheString</li>
<li>Boolean: @Data?.TheBoolean</li>
</ul>
</div>
</div>
@code {
[Parameter]
public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; }
}
RenderNamedTupleParent.razor:
@page "/render-named-tuple-parent"
<h1>Render Named Tuple Parent</h1>
<RenderNamedTupleChild Data="data" />
@code {
private (int TheInteger, string TheString, bool TheBoolean) data =
new(999, "I aim to misbehave.", true);
}
引用 ©2005 Universal Pictures: Serenity (Nathan Fillion)
路由參數
元件可以在 @page 指示詞的路由範本中指定路由參數。
Blazor 路由器會使用路由參數來填入對應的元件參數。
RouteParameter1.razor:
@page "/route-parameter-1/{text}"
<PageTitle>Route Parameter 1</PageTitle>
<h1>Route Parameter Example 1</h1>
<p>Blazor is @Text!</p>
@code {
[Parameter]
public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"
<PageTitle>Route Parameter 1</PageTitle>
<h1>Route Parameter Example 1</h1>
<p>Blazor is @Text!</p>
@code {
[Parameter]
public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string Text { get; set; }
}
@page "/route-parameter-1/{text}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string Text { get; set; }
}
如需詳細資訊,請參閱 中的Blazor 一節。 此外也支援選擇性路由參數,同一節有其相關說明。 如需有關可跨多個資料夾界限來擷取路徑的 catch-all 路由參數 ({*pageRoute}) 的資訊,請參閱 的Blazor一節。
如需詳細資訊,請參閱 中的Blazor 一節。 不支援選擇性路由參數,因此需要兩個 @page 指示詞 (如需詳細資訊,請參閱路由參數一節)。 如需有關可跨多個資料夾界限來擷取路徑的 catch-all 路由參數 ({*pageRoute}) 的資訊,請參閱 的Blazor一節。
警告
透過預設啟用的壓縮,避免建立安全 (經過驗證/授權) 的互動式伺服器端元件來呈現來自不受信任來源的資料。 不受信任的來源包括路由參數、查詢字串、來自 JS 互通性的資料,以及第三方使用者可以控制的任何其他資料來源 (資料庫、外部服務)。 如需詳細資訊,請參閱 ASP.NET Core BlazorSignalR 指引和 ASP.NET Core Blazor 互動式伺服器端轉譯的威脅防護指引。
子內容渲染片段
元件可以設定另一個元件的內容。 指派方元件會提供子元件的開頭和結束標籤之間的內容。
在下列範例中,RenderFragmentChild 元件具有 ChildContent 元件參數,此參數代表要轉譯為 RenderFragment 的 UI 區段。
ChildContent 在元件 Razor 標記中的位置,正是內容在最終 HTML 輸出時的呈現位置。
RenderFragmentChild.razor:
<div class="card w-25" style="margin-bottom:15px">
<div class="card-header font-weight-bold">Child content</div>
<div class="card-body">@ChildContent</div>
</div>
@code {
[Parameter]
public RenderFragment? ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
<div class="card-header font-weight-bold">Child content</div>
<div class="card-body">@ChildContent</div>
</div>
@code {
[Parameter]
public RenderFragment? ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
<div class="card-header font-weight-bold">Child content</div>
<div class="card-body">@ChildContent</div>
</div>
@code {
[Parameter]
public RenderFragment? ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
<div class="card-header font-weight-bold">Child content</div>
<div class="card-body">@ChildContent</div>
</div>
@code {
[Parameter]
public RenderFragment? ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
<div class="card-header font-weight-bold">Child content</div>
<div class="card-body">@ChildContent</div>
</div>
@code {
[Parameter]
public RenderFragment ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
<div class="card-header font-weight-bold">Child content</div>
<div class="card-body">@ChildContent</div>
</div>
@code {
[Parameter]
public RenderFragment ChildContent { get; set; }
}
下列元件會藉由將內容放在子元件的開頭和結束標籤內,來提供用於轉譯 RenderFragmentChild 的內容。
RenderFragments.razor:
@page "/render-fragments"
<PageTitle>Render Fragments</PageTitle>
<h1>Render Fragments Example</h1>
<RenderFragmentChild>
Content of the child component is supplied
by the parent component.
</RenderFragmentChild>
RenderFragments.razor:
@page "/render-fragments"
<PageTitle>Render Fragments</PageTitle>
<h1>Render Fragments Example</h1>
<RenderFragmentChild>
Content of the child component is supplied
by the parent component.
</RenderFragmentChild>
RenderFragmentParent.razor:
@page "/render-fragment-parent"
<h1>Render child content</h1>
<RenderFragmentChild>
Content of the child component is supplied
by the parent component.
</RenderFragmentChild>
RenderFragmentParent.razor:
@page "/render-fragment-parent"
<h1>Render child content</h1>
<RenderFragmentChild>
Content of the child component is supplied
by the parent component.
</RenderFragmentChild>
RenderFragmentParent.razor:
@page "/render-fragment-parent"
<h1>Render child content</h1>
<RenderFragmentChild>
Content of the child component is supplied
by the parent component.
</RenderFragmentChild>
RenderFragmentParent.razor:
@page "/render-fragment-parent"
<h1>Render child content</h1>
<RenderFragmentChild>
Content of the child component is supplied
by the parent component.
</RenderFragmentChild>
在整個 Blazor 應用程式中,呈現片段用於呈現子內容,以下文章及文章內的章節中附有範例進行相關說明:
注意
Blazor 架構的內建 Razor 元件會使用相同的 ChildContent 元件參數慣例來設定其內容。 若要辨識設定子內容的元件,請在 ChildContent搜尋元件參數屬性名稱 (使用「ChildContent」作為搜尋篩選條件)。
轉譯可重複使用轉譯邏輯的片段
您可以透過單純重複使用轉譯邏輯的方式來分解子元件。 在任何元件的 @code 區塊中,定義 RenderFragment,並視需要從任何位置轉譯片段任意次數:
@RenderWelcomeInfo
<p>Render the welcome info a second time:</p>
@RenderWelcomeInfo
@code {
private RenderFragment RenderWelcomeInfo = @<p>Welcome to your new app!</p>;
}
如需詳細資訊,請參閱重複使用轉譯邏輯。
具有元件參數和子內容的迴圈變數
在 for 迴圈內轉譯元件時,如果元件的參數或 RenderFragment 子內容使用了遞增迴圈變數,則需要使用本機索引變數。
請考慮下列 RenderFragmentChild2 元件,它具有元件參數 (Id) 和用來顯示子內容的轉譯片段 (ChildContent)。
RenderFragmentChild2.razor:
<div class="card w-25" style="margin-bottom:15px">
<div class="card-header font-weight-bold">Child content (@Id)</div>
<div class="card-body">@ChildContent</div>
</div>
@code {
[Parameter]
public string? Id { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
}
在上層元件中轉譯 RenderFragmentChild2 元件時,請在指派元件參數值並提供子元件的內容時,使用本機索引變數 (下列範例中的 ct) 而不是迴圈變數 (c):
@for (int c = 1; c < 4; c++)
{
var ct = c;
<RenderFragmentChild2 Id="@($"Child{ct}")">
Count: @ct
</RenderFragmentChild2>
}
或者,使用 foreach 迴圈並搭配 Enumerable.Range ,而不是使用 for 迴圈。
@foreach (var c in Enumerable.Range(1, 3))
{
<RenderFragmentChild2 Id="@($"Child{c}")">
Count: @c
</RenderFragmentChild2>
}
擷取元件的參考
元件參考提供了一種方法,讓您能夠引用元件執行個體以發出命令。 若要擷取元件參考:
- 將
@ref屬性新增至子元件。 - 定義與子元件相同類型的欄位。
元件渲染時,欄位會填入元件的實例。 接著,您便可以叫用執行個體上的 .NET 方法。
請考慮下列會在呼叫其 ReferenceChild 時記錄訊息的 ChildMethod 元件。
ReferenceChild.razor:
@inject ILogger<ReferenceChild> Logger
@if (value > 0)
{
<p>
<code>value</code>: @value
</p>
}
@code {
private int value;
public void ChildMethod(int value)
{
Logger.LogInformation("Received {Value} in ChildMethod", value);
this.value = value;
StateHasChanged();
}
}
@inject ILogger<ReferenceChild> Logger
@if (value > 0)
{
<p>
<code>value</code>: @value
</p>
}
@code {
private int value;
public void ChildMethod(int value)
{
Logger.LogInformation("Received {Value} in ChildMethod", value);
this.value = value;
StateHasChanged();
}
}
@using Microsoft.Extensions.Logging
@inject ILogger<ReferenceChild> Logger
@code {
public void ChildMethod(int value)
{
Logger.LogInformation("Received {Value} in ChildMethod", value);
}
}
@using Microsoft.Extensions.Logging
@inject ILogger<ReferenceChild> Logger
@code {
public void ChildMethod(int value)
{
Logger.LogInformation("Received {Value} in ChildMethod", value);
}
}
@using Microsoft.Extensions.Logging
@inject ILogger<ReferenceChild> Logger
@code {
public void ChildMethod(int value)
{
Logger.LogInformation("Received {Value} in ChildMethod", value);
}
}
@using Microsoft.Extensions.Logging
@inject ILogger<ReferenceChild> Logger
@code {
public void ChildMethod(int value)
{
Logger.LogInformation("Received {Value} in ChildMethod", value);
}
}
只有在元件已轉譯且其輸出包含 ReferenceChild 的元素之後,才會填入元件參考。 在元件被呈現之前,沒有任何可以參考的對象。 請勿嘗試直接呼叫事件處理常式的參考元件方法 (例如 @onclick="childComponent!.ChildMethod(5)"),因為在指派點擊事件時可能尚未指派參考變數。
若要在元件完成轉譯之後操作元件參考,請使用 OnAfterRender 或 OnAfterRenderAsync 方法。
下列範例使用上述 ReferenceChild 元件。
ReferenceParent.razor:
@page "/reference-parent"
<div>
<button @onclick="@(() => childComponent1!.ChildMethod(5))">
Call <code>ReferenceChild.ChildMethod</code> (first instance)
with an argument of 5
</button>
<ReferenceChild @ref="childComponent1" />
</div>
<div>
<button @onclick="CallChildMethod">
Call <code>ReferenceChild.ChildMethod</code> (second instance)
with an argument of 5
</button>
<ReferenceChild @ref="childComponent2" />
</div>
@code {
private ReferenceChild? childComponent1;
private ReferenceChild? childComponent2;
private void CallChildMethod() => childComponent2!.ChildMethod(5);
}
@page "/reference-parent"
<div>
<button @onclick="@(() => childComponent1!.ChildMethod(5))">
Call <code>ReferenceChild.ChildMethod</code> (first instance)
with an argument of 5
</button>
<ReferenceChild @ref="childComponent1" />
</div>
<div>
<button @onclick="CallChildMethod">
Call <code>ReferenceChild.ChildMethod</code> (second instance)
with an argument of 5
</button>
<ReferenceChild @ref="childComponent2" />
</div>
@code {
private ReferenceChild? childComponent1;
private ReferenceChild? childComponent2;
private void CallChildMethod() => childComponent2!.ChildMethod(5);
}
@page "/reference-parent"
<div>
<button @onclick="@(() => childComponent1!.ChildMethod(5))">
Call <code>ReferenceChild.ChildMethod</code> (first instance)
with an argument of 5
</button>
<ReferenceChild @ref="childComponent1" />
</div>
<div>
<button @onclick="CallChildMethod">
Call <code>ReferenceChild.ChildMethod</code> (second instance)
with an argument of 5
</button>
<ReferenceChild @ref="childComponent2" />
</div>
@code {
private ReferenceChild? childComponent1;
private ReferenceChild? childComponent2;
private void CallChildMethod()
{
childComponent2!.ChildMethod(5);
}
}
@page "/reference-parent"
<div>
<button @onclick="@(() => childComponent1!.ChildMethod(5))">
Call <code>ReferenceChild.ChildMethod</code> (first instance)
with an argument of 5
</button>
<ReferenceChild @ref="childComponent1" />
</div>
<div>
<button @onclick="CallChildMethod">
Call <code>ReferenceChild.ChildMethod</code> (second instance)
with an argument of 5
</button>
<ReferenceChild @ref="childComponent2" />
</div>
@code {
private ReferenceChild? childComponent1;
private ReferenceChild? childComponent2;
private void CallChildMethod()
{
childComponent2!.ChildMethod(5);
}
}
@page "/reference-parent"
<div>
<button @onclick="@(() => childComponent1!.ChildMethod(5))">
Call <code>ReferenceChild.ChildMethod</code> (first instance)
with an argument of 5
</button>
<ReferenceChild @ref="childComponent1" />
</div>
<div>
<button @onclick="CallChildMethod">
Call <code>ReferenceChild.ChildMethod</code> (second instance)
with an argument of 5
</button>
<ReferenceChild @ref="childComponent2" />
</div>
@code {
private ReferenceChild childComponent1;
private ReferenceChild childComponent2;
private void CallChildMethod()
{
childComponent2!.ChildMethod(5);
}
}
@page "/reference-parent"
<div>
<button @onclick="@(() => childComponent1!.ChildMethod(5))">
Call <code>ReferenceChild.ChildMethod</code> (first instance)
with an argument of 5
</button>
<ReferenceChild @ref="childComponent1" />
</div>
<div>
<button @onclick="CallChildMethod">
Call <code>ReferenceChild.ChildMethod</code> (second instance)
with an argument of 5
</button>
<ReferenceChild @ref="childComponent2" />
</div>
@code {
private ReferenceChild childComponent1;
private ReferenceChild childComponent2;
private void CallChildMethod()
{
childComponent2!.ChildMethod(5);
}
}
雖然擷取元件參考會使用類似於擷取元素參考的語法,但擷取元件參考不是 JavaScript 的 Interop 功能。 元件參考不會傳遞至 JavaScript 程式碼。 元件參考只會用於 .NET 程式碼。
重要
請勿使用元件參考來改變子元件的狀態。 請改用一般宣告式元件參數,將資料傳遞至子元件。 使用元件參數會使子元件在正確的時間自動重新渲染。 如需詳細資訊,請參閱元件參數一節和 ASP.NET Core Blazor 資料繫結一文。
套用屬性
您可以使用 @attribute 指示詞將屬性套用至元件。 下列範例會將 [Authorize] 屬性套用至元件的類別:
@page "/"
@attribute [Authorize]
條件式 HTML 元素屬性和 DOM 屬性
Blazor 採用下列一般行為:
- 對於 HTML 屬性,Blazor 會根據 .NET 值有條件地設定或移除屬性。 如果 .NET 值是
false或null,則不會設定該屬性,或者如果先前已設定該屬性,則會將其移除。 - 對於 DOM 屬性 (例如
checked或value),Blazor 會根據 .NET 值設定 DOM 屬性。 如果 .NET 值是false或null,則 DOM 屬性會重設為預設值。
哪些 Razor 語法屬性對應於 HTML 屬性,哪些對應於 DOM 屬性會保持未記載,因為其是架構實作細節,可能會在不通知的情況下變更。
警告
某些 HTML 屬性 (例如 aria-pressed) 必須具有「true」或「false」的字串值。 由於它們需要字串值而不是布林值,因此您必須使用 .NET string 而不是 bool 作為它們的值。 這是瀏覽器 DOM API 所設定的需求。
原始 HTML
字串一般會使用 DOM 文字節點來進行轉譯,這表示其可能包含的任何標記都會遭到忽略並視為常值文字。 若要轉譯原始 HTML,請將 HTML 內容包裝到 MarkupString 值內。 此值會剖析為 HTML 或 SVG,並插入到 DOM。
警告
針對從任何不受信任的來源所建構的原始 HTML 進行轉譯會有安全性風險,請一律避免此行為。
下列範例示範如何使用 MarkupString 類型,將靜態 HTML 內容的區塊新增至元件的轉譯輸出。
MarkupStrings.razor:
@page "/markup-strings"
<PageTitle>Markup Strings</PageTitle>
<h1>Markup Strings Example</h1>
@((MarkupString)myMarkup)
@code {
private string myMarkup =
"<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}
MarkupStrings.razor:
@page "/markup-strings"
<PageTitle>Markup Strings</PageTitle>
<h1>Markup Strings Example</h1>
@((MarkupString)myMarkup)
@code {
private string myMarkup =
"<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}
MarkupStringExample.razor:
@page "/markup-string-example"
@((MarkupString)myMarkup)
@code {
private string myMarkup =
"<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}
MarkupStringExample.razor:
@page "/markup-string-example"
@((MarkupString)myMarkup)
@code {
private string myMarkup =
"<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}
MarkupStringExample.razor:
@page "/markup-string-example"
@((MarkupString)myMarkup)
@code {
private string myMarkup =
"<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}
MarkupStringExample.razor:
@page "/markup-string-example"
@((MarkupString)myMarkup)
@code {
private string myMarkup =
"<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}
Razor 範本
您可以使用 Razor 範本語法來定義轉譯片段或 UI 程式碼片段。 Razor 範本會使用下列格式:
@<{HTML tag}>...</{HTML tag}>
下列範例說明如何直接在元件中指定 RenderFragment 和 RenderFragment<TValue> 的值並轉譯範本。 轉譯片段也可以作為引數傳遞至樣板化元件。
RazorTemplate.razor:
@page "/razor-template"
<PageTitle>Razor Template</PageTitle>
<h1>Razor Template Example</h1>
@timeTemplate
@petTemplate(new Pet { Name = "Nutty Rex" })
@code {
private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;
private class Pet
{
public string? Name { get; set; }
}
}
@page "/razor-template"
<PageTitle>Razor Template</PageTitle>
<h1>Razor Template Example</h1>
@timeTemplate
@petTemplate(new Pet { Name = "Nutty Rex" })
@code {
private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;
private class Pet
{
public string? Name { get; set; }
}
}
@page "/razor-template"
@timeTemplate
@petTemplate(new Pet { Name = "Nutty Rex" })
@code {
private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;
private class Pet
{
public string? Name { get; set; }
}
}
@page "/razor-template"
@timeTemplate
@petTemplate(new Pet { Name = "Nutty Rex" })
@code {
private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;
private class Pet
{
public string? Name { get; set; }
}
}
@page "/razor-template"
@timeTemplate
@petTemplate(new Pet { Name = "Nutty Rex" })
@code {
private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;
private class Pet
{
public string Name { get; set; }
}
}
@page "/razor-template"
@timeTemplate
@petTemplate(new Pet { Name = "Nutty Rex" })
@code {
private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;
private class Pet
{
public string Name { get; set; }
}
}
上述程式碼的轉譯輸出:
<p>The time is 4/19/2021 8:54:46 AM.</p>
<p>Pet: Nutty Rex</p>
靜態資產
Blazor 會遵循靜態資產的 ASP.NET Core 應用程式慣例。 靜態資產位於專案的 web root (wwwroot) 資料夾內,或是 wwwroot 資料夾底下的資料夾內。
請使用基底相對路徑 (/) 來參考靜態資產的 Web 根目錄。 在下列範例中,logo.png 實際位於 {PROJECT ROOT}/wwwroot/images 資料夾中。
{PROJECT ROOT} 是應用程式的專案根目錄。
<img alt="Company logo" src="/images/logo.png" />
元件不支援波浪線斜線表示法 (~/)。
如需設定應用程式基底路徑的資訊,請參閱 ASP.NET Core Blazor 應用程式基底路徑。
元件不支援標籤協助工具
元件不支援Tag Helpers。 若要在 Blazor 中提供類似標籤協助程式的功能,請建立功能與標籤協助程式相同的元件,並改用該元件。
可縮放向量圖形 (SVG) 影像
由於 Blazor 會轉譯 HTML,因此包括可縮放向量圖形 (SVG) 影像 (.svg) 在內的瀏覽器支援影像可透過 <img> 標籤而獲得支援:
<img alt="Example image" src="image.svg" />
同樣地,樣式表檔案的 CSS 規則 (.css) 也支援 SVG 影像:
.element-class {
background-image: url("image.svg");
}
Blazor 會支援 <foreignObject> 元素,以便顯示 SVG 內的任意 HTML。 標記可以代表任意 HTML、RenderFragment 或 Razor 元件。
下列範例會示範:
- 顯示
string(@message)。 -
<input>元素和value欄位的雙向繫結。 -
Robot元件。
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" rx="10" ry="10" width="200" height="200" stroke="black"
fill="none" />
<foreignObject x="20" y="20" width="160" height="160">
<p>@message</p>
</foreignObject>
</svg>
<svg xmlns="http://www.w3.org/2000/svg">
<foreignObject width="200" height="200">
<label>
Two-way binding:
<input @bind="value" @bind:event="oninput" />
</label>
</foreignObject>
</svg>
<svg xmlns="http://www.w3.org/2000/svg">
<foreignObject>
<Robot />
</foreignObject>
</svg>
@code {
private string message = "Lorem ipsum dolor sit amet, consectetur adipiscing " +
"elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
private string? value;
}
空白字元渲染行為
除非 @preservewhitespace 指示詞與 true 值搭配使用,否則如果有下列情況,系統會移除額外的空白字元:
- 在元素中處於前置或後置位置。
- 在 RenderFragment/RenderFragment<TValue> 參數內前置或後置 (例如,子內容傳遞至另一個元件)。
- 其在 C# 程式碼區塊之前或之後,例如
@if或@foreach。
使用 CSS 規則時,移除空白字元可能會影響經過轉譯的輸出,例如 white-space: pre。 若要停用此效能最佳化功能並保留空白字元,請採取下列其中一個動作:
- 在
@preservewhitespace true檔案 (Razor) 頂端新增.razor指示詞,以將喜好設定套用至特定元件。 - 在
@preservewhitespace true檔案內新增_Imports.razor指示詞,以將喜好設定套用至子目錄或整個專案。
在大部分情況下,您不需要採取任何動作,因為應用程式通常會繼續正常運作 (但速度會更快)。 如果移除空白字元會導致特定元件發生轉譯問題,請在該元件中使用 @preservewhitespace true 來停用此最佳化。
空白字元會保留在元件的來源標記中。 只有空白字元的文字會在瀏覽器的 DOM 中呈現,即使不會產生視覺效果。
請考慮下列元件標記:
<ul>
@foreach (var item in Items)
{
<li>
@item.Text
</li>
}
</ul>
上述範例會呈現下列不必要的空白:
- 位於
@foreach程式碼區塊外部。 - 在
<li>元素周圍。 - 在
@item.Text輸出周圍。
100 個項目的清單會產生超過 400 個空白字元區域。 無論有多少額外的空白字元,都不會在視覺上影響呈現的結果。
在轉譯元件的靜態 HTML 時,不會保留標籤內的空白字元。 例如,在元件 <img> 檔案中檢視下列 Razor 標籤的轉譯輸出 (.razor):
<img alt="Example image" src="img.png" />
從前面的標記中,空白字元沒有被保留:
<img alt="Example image" src="img.png" />
根元件
根 Razor 元件 (根元件) 是在應用程式所建立的任何元件階層中第一個載入的元件。
在由 Blazor Web App 專案範本建立的應用程式中,App 元件 (App.razor) 被指定為預設根元件,這是透過伺服器端 MapRazorComponents<TRootComponent> 檔案中呼叫 Program 所宣告的型別參數來實現的。 下列範例示範使用 App 元件做為根元件,這是從 Blazor 專案範本所建立應用程式的預設值:
app.MapRazorComponents<App>();
注意
不支援讓根元件成為互動式,例如 App 元件。
在從 Blazor Server 專案範本建立的應用程式中,App 元件 (App.razor) 被指定為預設根元件,這是透過 Pages/_Host.cshtml 在 中實現的。
<component type="typeof(App)" render-mode="ServerPrerendered" />
在從 Blazor WebAssembly 專案範本建立的應用程式中,App 元件 (App.razor) 會指定為 Program 檔案中的預設根元件:
builder.RootComponents.Add<App>("#app");
在上述程式碼中,CSS 選取器 #app 表示已在 App 中針對 <div> 指定具有 wwwroot/index.html: id 的 app 元件。
<div id="app">...</app>
MVC 和 Razor Pages 應用程式也可以使用元件標籤輔助器來註冊靜態轉譯的 Blazor WebAssembly 根元件:
<component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
靜態渲染的元件只能新增至應用程式。 之後無法移除或更新這些元件。
如需詳細資訊,請參閱以下資源: