建立和使用 ASP.NET Core Razor 元件Create and use ASP.NET Core Razor components

Luke LathamDaniel RothTobias BartschBy Luke Latham, Daniel Roth, and Tobias Bartsch

查看或下載範例程式碼 (如何下載) View or download sample code (how to download)

Blazor 應用程式是使用 元件建立的。Blazor apps are built using components. 元件是獨立的使用者介面區塊, (UI) ,例如頁面、對話方塊或表單。A component is a self-contained chunk of user interface (UI), such as a page, dialog, or form. 元件包含 HTML 標籤以及插入資料或回應 UI 事件所需的處理邏輯。A component includes HTML markup and the processing logic required to inject data or respond to UI events. 元件具有彈性和輕量。Components are flexible and lightweight. 這些專案可以在專案之間進行嵌套、重複使用及共用。They can be nested, reused, and shared among projects.

元件類別Component classes

元件會 Razor .razor 使用 c # 和 HTML 標籤的組合,在元件檔 () 中實作為元件。Components are implemented in Razor component files (.razor) using a combination of C# and HTML markup. 中的元件 Blazor 正式參考為* Razor 元件*。A component in Blazor is formally referred to as a Razor component.

Razor 語法Razor syntax

Razor 應用程式中的元件會 Blazor 廣泛使用 Razor 語法。Razor components in Blazor apps extensively use Razor syntax. 如果您不熟悉 Razor 標記語言,建議您 ASP.NET Core 的 razor 語法參考 在繼續之前先閱讀。If you aren't familiar with the Razor markup language, we recommend reading ASP.NET Core 的 razor 語法參考 before proceeding.

存取語法上的內容時 Razor ,請特別注意下列各節:When accessing the content on Razor syntax, pay special attention to the following sections:

  • Directives @ 指示詞:前置詞保留關鍵字,通常會變更元件標記的剖析或運作方式。Directives: @-prefixed reserved keywords that typically change the way component markup is parsed or function.
  • Directive attributes @ 指示詞屬性:-前置詞,通常會變更元件元素剖析或運作的方式。Directive attributes: @-prefixed reserved keywords that typically change the way component elements are parsed or function.

名稱Names

元件的名稱必須以大寫字元開頭。A component's name must start with an uppercase character. 例如, MyCoolComponent.razor 有效,且 myCoolComponent.razor 無效。For example, MyCoolComponent.razor is valid, and myCoolComponent.razor is invalid.

路由Routing

中的路由傳送 Blazor 可透過提供應用程式中每個可存取元件的路由範本來達成。Routing in Blazor is achieved by providing a route template to each accessible component in the app. 當編譯具有指示詞的檔案時 Razor @page ,產生的類別會 RouteAttribute 指定路由範本。When a Razor file with an @page directive is compiled, the generated class is given a RouteAttribute specifying the route template. 在執行時間,路由器會尋找具有的元件類別 RouteAttribute ,並轉譯任何元件具有符合所要求 URL 的路由範本。At runtime, the router looks for component classes with a RouteAttribute and renders whichever component has a route template that matches the requested URL. 如需詳細資訊,請參閱ASP.NET Core Blazor 路由For more information, see ASP.NET Core Blazor 路由.

@page "/ParentComponent"

...

標記Markup

元件的 UI 是使用 HTML 來定義。The UI for a component is defined using HTML. 動態轉譯邏輯 (例如,迴圈、條件、運算式) 是使用稱為的內嵌 c # 語法來新增 RazorDynamic rendering logic (for example, loops, conditionals, expressions) is added using an embedded C# syntax called Razor. 當編譯應用程式時,會將 HTML 標籤和 c # 轉譯邏輯轉換成元件類別。When an app is compiled, the HTML markup and C# rendering logic are converted into a component class. 產生之類別的名稱符合檔案名。The name of the generated class matches the name of the file.

元件類別的成員是在區塊中定義 @codeMembers of the component class are defined in an @code block. @code 區塊中,[元件狀態] ([屬性]、[欄位]) 是以事件處理方法或定義其他元件邏輯的方法所指定。In the @code block, component state (properties, fields) is specified with methods for event handling or for defining other component logic. 允許一個以上 @code 的區塊。More than one @code block is permissible.

元件成員可以使用以開頭的 c # 運算式作為元件轉譯邏輯的一部分 @Component members can be used as part of the component's rendering logic using C# expressions that start with @. 例如,c # 欄位的呈現方式是在功能變數名稱前面加上 @For example, a C# field is rendered by prefixing @ to the field name. 下列範例會評估和轉譯:The following example evaluates and renders:

  • headingFontStyle 至的 CSS 屬性值 font-styleheadingFontStyle to the CSS property value for font-style.
  • headingText 至元素的內容 <h1>headingText to the content of the <h1> element.
<h1 style="font-style:@headingFontStyle">@headingText</h1>

@code {
    private string headingFontStyle = "italic";
    private string headingText = "Put on your new Blazor!";
}

在元件一開始呈現之後,元件會重新產生其轉譯樹狀結構,以回應事件。After the component is initially rendered, the component regenerates its render tree in response to events. Blazor 然後比較新的轉譯樹狀結構與上一個樹狀結構,並將任何修改套用至瀏覽器的檔物件模型 (DOM) 。Blazor then compares the new render tree against the previous one and applies any modifications to the browser's Document Object Model (DOM).

元件是一般的 c # 類別,可放在專案內的任何位置。Components are ordinary C# classes and can be placed anywhere within a project. 產生網頁的元件通常位於資料夾中 PagesComponents that produce webpages usually reside in the Pages folder. 非頁面元件通常會放在資料夾中, Shared 或加入至專案的自訂資料夾中。Non-page components are frequently placed in the Shared folder or a custom folder added to the project.

命名空間Namespaces

一般而言,元件的命名空間是從應用程式的根命名空間和元件在應用程式中) (資料夾的位置衍生。Typically, a component's namespace is derived from the app's root namespace and the component's location (folder) within the app. 如果應用程式的根命名空間為 BlazorSample ,而且 Counter 元件位於 Pages 資料夾中:If the app's root namespace is BlazorSample and the Counter component resides in the Pages folder:

  • Counter元件的命名空間為 BlazorSample.PagesThe Counter component's namespace is BlazorSample.Pages.
  • 元件的完整類型名稱為 BlazorSample.Pages.CounterThe fully qualified type name of the component is BlazorSample.Pages.Counter.

若為保存元件的自訂資料夾,請將指示詞新增 @using 至父元件或應用程式的檔案 _Imports.razorFor custom folders that hold components, add a @using directive to the parent component or to the app's _Imports.razor file. 下列範例會讓資料夾中的元件 Components 可供使用:The following example makes components in the Components folder available:

@using BlazorSample.Components

元件也可以使用其完整名稱來參考,而不需要指示詞 @usingComponents can also be referenced using their fully qualified names, which doesn't require the @using directive:

<BlazorSample.Components.MyComponent />

使用撰寫之元件的命名空間 Razor 是以優先權順序) 的 (為基礎:The namespace of a component authored with Razor is based on (in priority order):

  • @namespace 檔案 (中的指定 Razor .razor) 標記 (@namespace BlazorSample.MyNamespace) 。@namespace designation in Razor file (.razor) markup (@namespace BlazorSample.MyNamespace).
  • 專案檔中的專案會 RootNamespace (<RootNamespace>BlazorSample</RootNamespace>) 。The project's RootNamespace in the project file (<RootNamespace>BlazorSample</RootNamespace>).
  • 專案名稱(取自專案檔的檔案名 (.csproj) ),以及從專案根目錄到元件的路徑。The project name, taken from the project file's file name (.csproj), and the path from the project root to the component. 例如,架構會將 {PROJECT ROOT}/Pages/Index.razor (BlazorSample.csproj) 解析為命名空間 BlazorSample.PagesFor example, the framework resolves {PROJECT ROOT}/Pages/Index.razor (BlazorSample.csproj) to the namespace BlazorSample.Pages. 元件遵循 c # 名稱系結規則。Components follow C# name binding rules. 針對 Index 此範例中的元件,範圍中的元件都是所有的元件:For the Index component in this example, the components in scope are all of the components:
    • 在相同的資料夾中 PagesIn the same folder, Pages.
    • 專案根目錄中未明確指定不同命名空間的元件。The components in the project's root that don't explicitly specify a different namespace.

注意

global::不支援資格。The global:: qualification isn't supported.

使用別名語句匯入元件 using (例如, @using Foo = Bar 不支援) 。Importing components with aliased using statements (for example, @using Foo = Bar) isn't supported.

不支援部分限定名稱。Partially qualified names aren't supported. 例如, @using BlazorSample 不支援新增和參考 NavMenu 元件 (NavMenu.razor) <Shared.NavMenu></Shared.NavMenu>For example, adding @using BlazorSample and referencing the NavMenu component (NavMenu.razor) with <Shared.NavMenu></Shared.NavMenu> isn't supported.

部分類別支援Partial class support

Razor 元件會以部分類別的形式產生。Razor components are generated as partial classes. Razor 您可以使用下列其中一種方法來撰寫元件:Razor components are authored using either of the following approaches:

  • C # 程式碼是以 @code 單一檔案中的 HTML 標籤和程式碼區塊來定義 Razor 。C# code is defined in an @code block with HTML markup and Razor code in a single file. Blazor 範本會 Razor 使用這種方法來定義其元件。Blazor templates define their Razor components using this approach.
  • C # 程式碼會放在定義為部分類別的程式碼後置檔案中。C# code is placed in a code-behind file defined as a partial class.

下列範例顯示 Counter @code 從範本產生的應用程式中有區塊的預設元件 Blazor 。The following example shows the default Counter component with an @code block in an app generated from a Blazor template. HTML 標籤、程式 Razor 代碼和 c # 程式碼位於相同的檔案中:HTML markup, Razor code, and C# code are in the same file:

Pages/Counter.razor:Pages/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;

    void IncrementCount()
    {
        currentCount++;
    }
}

Counter元件也可以使用具有部分類別的程式碼後端檔案來建立:The Counter component can also be created using a code-behind file with a partial class:

Pages/Counter.razor:Pages/Counter.razor:

@page "/counter"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

Counter.razor.cs:Counter.razor.cs:

namespace BlazorSample.Pages
{
    public partial class Counter
    {
        private int currentCount = 0;

        void IncrementCount()
        {
            currentCount++;
        }
    }
}

視需要將任何必要的命名空間加入至部分類別檔案。Add any required namespaces to the partial class file as needed. 元件所使用的一般命名空間 Razor 包括:Typical namespaces used by Razor components include:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Web;

重要

@using 檔案中的指示詞 _Imports.razor 只會套用至檔案 Razor (.razor) ,而非 c # 檔案 (.cs) 。@using directives in the _Imports.razor file are only applied to Razor files (.razor), not C# files (.cs).

指定基類Specify a base class

指示詞 @inherits 可以用來指定元件的基類。The @inherits directive can be used to specify a base class for a component. 下列範例會顯示元件如何繼承基類, BlazorRocksBase 以提供元件的屬性和方法。The following example shows how a component can inherit a base class, BlazorRocksBase, to provide the component's properties and methods. 基類應衍生自 ComponentBaseThe base class should derive from ComponentBase.

Pages/BlazorRocks.razor:Pages/BlazorRocks.razor:

@page "/BlazorRocks"
@inherits BlazorRocksBase

<h1>@BlazorRocksText</h1>

BlazorRocksBase.cs:BlazorRocksBase.cs:

using Microsoft.AspNetCore.Components;

namespace BlazorSample
{
    public class BlazorRocksBase : ComponentBase
    {
        public string BlazorRocksText { get; set; } = 
            "Blazor rocks the browser!";
    }
}

使用元件Use components

元件可以使用 HTML 元素語法來宣告它們,以包含其他元件。Components can include other components by declaring them using HTML element syntax. 使用元件的標記看起來像是 HTML 標籤,其中標籤名稱是元件類型。The markup for using a component looks like an HTML tag where the name of the tag is the component type.

中的下列標記會 Pages/Index.razor 呈現 HeadingComponent 實例:The following markup in Pages/Index.razor renders a HeadingComponent instance:

<HeadingComponent />

Components/HeadingComponent.razor:Components/HeadingComponent.razor:

@using System.Globalization

<h1 style="font-style:@headingFontStyle">@headingText</h1>

<form>
    <div>
        <label class="form-check-label">
            <input type="checkbox" id="italicsCheck" 
               @bind="italicsCheck" />
            Use italics
        </label>
    </div>

    <button type="button" class="btn btn-primary" @onclick="UpdateHeading">
        Update heading
    </button>
</form>

@code {
    private static TextInfo tinfo = CultureInfo.CurrentCulture.TextInfo;
    private string headingText = 
        tinfo.ToTitleCase("welcome to blazor!");
    private string headingFontStyle = "normal";
    private bool italicsCheck = false;

    public void UpdateHeading()
    {
        headingFontStyle = italicsCheck ? "italic" : "normal";
    }
}

如果元件包含的 HTML 元素具有不符合元件名稱的大寫第一個字母,則會發出警告,指出元素有未預期的名稱。If a component contains an HTML element with an uppercase first letter that doesn't match a component name, a warning is emitted indicating that the element has an unexpected name. 新增 @using 元件命名空間的指示詞會讓元件可供使用,以解決警告。Adding an @using directive for the component's namespace makes the component available, which resolves the warning.

參數Parameters

路由參數Route parameters

元件可以從指示詞中提供的路由範本接收路由參數 @pageComponents can receive route parameters from the route template provided in the @page directive. 路由器會使用路由參數來填入對應的元件參數。The router uses route parameters to populate the corresponding component parameters.

Pages/RouteParameter.razor:Pages/RouteParameter.razor:

@page "/RouteParameter"
@page "/RouteParameter/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string Text { get; set; }

    protected override void OnInitialized()
    {
        Text = Text ?? "fantastic";
    }
}

不支援選擇性參數,因此 @page 在上述範例中會套用兩個指示詞。Optional parameters aren't supported, so two @page directives are applied in the preceding example. 第一個可讓您在不使用參數的情況下流覽至元件。The first permits navigation to the component without a parameter. 第二個指示詞會 @page 接收 {text} route 參數,並將值指派給 Text 屬性。The second @page directive receives the {text} route parameter and assigns the value to the Text property.

如需捕捉所有路由參數的詳細資訊 ({*pageRoute}) ,以在多個資料夾界限之間取得路徑,請參閱 ASP.NET Core Blazor 路由For information on catch-all route parameters ({*pageRoute}), which capture paths across multiple folder boundaries, see ASP.NET Core Blazor 路由.

元件參數Component parameters

元件可以有 元件參數,這些參數是使用元件類別上的公用屬性(attribute)來定義的 [Parameter]Components can have component parameters, which are defined using public properties on the component class with the [Parameter] attribute. 使用這些屬性來指定標記中元件的引數。Use attributes to specify arguments for a component in markup.

Components/ChildComponent.razor:Components/ChildComponent.razor:

<div class="panel panel-default">
    <div class="panel-heading">@Title</div>
    <div class="panel-body">@ChildContent</div>

    <button class="btn btn-primary" @onclick="OnClickCallback">
        Trigger a Parent component method
    </button>
</div>

@code {
    [Parameter]
    public string Title { get; set; }

    [Parameter]
    public RenderFragment ChildContent { get; set; }

    [Parameter]
    public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}

在範例應用程式的下列範例中,會 ParentComponent 設定的 Title 屬性值 ChildComponentIn the following example from the sample app, the ParentComponent sets the value of the Title property of the ChildComponent.

Pages/ParentComponent.razor:Pages/ParentComponent.razor:

@page "/ParentComponent"

<h1>Parent-child example</h1>

<ChildComponent Title="Panel Title from Parent"
                OnClickCallback="@ShowMessage">
    Content of the child component is supplied
    by the parent component.
</ChildComponent>

警告

請勿建立會寫入其本身 元件參數的元件,而是改用私用欄位。Don't create components that write to their own component parameters, use a private field instead. 如需詳細資訊,請參閱 覆寫的參數 一節。For more information, see the Overwritten parameters section.

子內容Child content

元件可以設定另一個元件的內容。Components can set the content of another component. 指派元件會在指定接收元件的標記之間提供內容。The assigning component provides the content between the tags that specify the receiving component.

在下列範例中, ChildComponent 有一個 ChildContent 代表的屬性 RenderFragment ,代表要轉譯的 UI 區段。In the following example, the ChildComponent has a ChildContent property that represents a RenderFragment, which represents a segment of UI to render. 的值位於 ChildContent 應呈現內容的元件標記中。The value of ChildContent is positioned in the component's markup where the content should be rendered. 的值 ChildContent 是從父元件接收,並在啟動程式面板內轉譯 panel-bodyThe value of ChildContent is received from the parent component and rendered inside the Bootstrap panel's panel-body.

Components/ChildComponent.razor:Components/ChildComponent.razor:

<div class="panel panel-default">
    <div class="panel-heading">@Title</div>
    <div class="panel-body">@ChildContent</div>

    <button class="btn btn-primary" @onclick="OnClickCallback">
        Trigger a Parent component method
    </button>
</div>

@code {
    [Parameter]
    public string Title { get; set; }

    [Parameter]
    public RenderFragment ChildContent { get; set; }

    [Parameter]
    public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}

注意

接收內容的屬性 RenderFragment 必須依照慣例命名 ChildContentThe property receiving the RenderFragment content must be named ChildContent by convention.

ParentComponent範例應用程式中的會將 ChildComponent 內容放在標記內,以提供轉譯的內容 <ChildComponent>The ParentComponent in the sample app can provide content for rendering the ChildComponent by placing the content inside the <ChildComponent> tags.

Pages/ParentComponent.razor:Pages/ParentComponent.razor:

@page "/ParentComponent"

<h1>Parent-child example</h1>

<ChildComponent Title="Panel Title from Parent"
                OnClickCallback="@ShowMessage">
    Content of the child component is supplied
    by the parent component.
</ChildComponent>

由於轉譯 Blazor 子內容的方式, for 如果在子元件的內容中使用遞增迴圈變數,則在迴圈內轉譯元件需要本機索引變數:Due to the way that Blazor renders child content, rendering components inside a for loop requires a local index variable if the incrementing loop variable is used in the child component's content:

@for (int c = 0; c < 10; c++)
{
    var current = c;
    <ChildComponent Param1="@c">
        Child Content: Count: @current
    </ChildComponent>
}

或者,使用 foreach 迴圈搭配 Enumerable.RangeAlternatively, use a foreach loop with Enumerable.Range:

@foreach(var c in Enumerable.Range(0,10))
{
    <ChildComponent Param1="@c">
        Child Content: Count: @c
    </ChildComponent>
}

屬性展開和任意參數Attribute splatting and arbitrary parameters

元件除了元件的宣告參數之外,還可以捕獲和轉譯其他屬性。Components can capture and render additional attributes in addition to the component's declared parameters. 您可以在字典中捕捉其他屬性,然後在使用指示詞轉譯元件時, splatted 至元素 @attributes Razor 。Additional attributes can be captured in a dictionary and then splatted onto an element when the component is rendered using the @attributes Razor directive. 當您定義的元件會產生支援各種自訂專案的標記專案時,此案例很有用。This scenario is useful when defining a component that produces a markup element that supports a variety of customizations. 例如,針對 <input> 支援許多參數的來個別定義屬性可能相當繁瑣。For example, it can be tedious to define attributes separately for an <input> that supports many parameters.

在下列範例中,第一個專案 <input> (id="useIndividualParams") 使用個別的元件參數,而第二個 <input> 元素 (id="useAttributesDict") 使用屬性展開:In the following example, the first <input> element (id="useIndividualParams") uses individual component parameters, while the second <input> element (id="useAttributesDict") uses attribute splatting:

<input id="useIndividualParams"
       maxlength="@maxlength"
       placeholder="@placeholder"
       required="@required"
       size="@size" />

<input id="useAttributesDict"
       @attributes="InputAttributes" />

@code {
    public string maxlength = "10";
    public string placeholder = "Input placeholder text";
    public string required = "required";
    public string size = "50";

    public Dictionary<string, object> InputAttributes { get; set; } =
        new Dictionary<string, object>()
        {
            { "maxlength", "10" },
            { "placeholder", "Input placeholder text" },
            { "required", "required" },
            { "size", "50" }
        };
}

參數的類型必須 IEnumerable<KeyValuePair<string, object>> IReadOnlyDictionary<string, object> 使用字串索引鍵來執行。The type of the parameter must implement IEnumerable<KeyValuePair<string, object>> or IReadOnlyDictionary<string, object> with string keys.

<input>使用這兩種方法的轉譯元素相同:The rendered <input> elements using both approaches is identical:

<input id="useIndividualParams"
       maxlength="10"
       placeholder="Input placeholder text"
       required="required"
       size="50">

<input id="useAttributesDict"
       maxlength="10"
       placeholder="Input placeholder text"
       required="required"
       size="50">

若要接受任意屬性,請使用 [Parameter] CaptureUnmatchedValues 屬性設定為的屬性來定義元件參數 trueTo accept arbitrary attributes, define a component parameter using the [Parameter] attribute with the CaptureUnmatchedValues property set to true:

@code {
    [Parameter(CaptureUnmatchedValues = true)]
    public Dictionary<string, object> InputAttributes { get; set; }
}

CaptureUnmatchedValues上的屬性 [Parameter] 可讓參數符合所有不符合任何其他參數的屬性。The CaptureUnmatchedValues property on [Parameter] allows the parameter to match all attributes that don't match any other parameter. 元件只能用來定義單一參數 CaptureUnmatchedValuesA component can only define a single parameter with CaptureUnmatchedValues. 搭配使用的屬性類型, CaptureUnmatchedValues 必須可從 Dictionary<string, object> 使用字串索引鍵來指派。The property type used with CaptureUnmatchedValues must be assignable from Dictionary<string, object> with string keys. IEnumerable<KeyValuePair<string, object>>IReadOnlyDictionary<string, object> 也是此案例中的選項。IEnumerable<KeyValuePair<string, object>> or IReadOnlyDictionary<string, object> are also options in this scenario.

@attributes相對於元素屬性位置的位置是很重要的。The position of @attributes relative to the position of element attributes is important. 在專案 @attributes 上 splatted 時,會由右至左處理屬性 (最後一個) 。When @attributes are splatted on the element, the attributes are processed from right to left (last to first). 請考慮下列使用元件的元件範例 ChildConsider the following example of a component that consumes a Child component:

ParentComponent.razor:ParentComponent.razor:

<ChildComponent extra="10" />

ChildComponent.razor:ChildComponent.razor:

<div @attributes="AdditionalAttributes" extra="5" />

[Parameter(CaptureUnmatchedValues = true)]
public IDictionary<string, object> AdditionalAttributes { get; set; }

Child元件的 extra 屬性會設定為的右邊 @attributesThe Child component's extra attribute is set to the right of @attributes. Parent <div> extra="5" 由於屬性是由右至左 (最後一個) 來處理,因此,在透過其他屬性傳遞時,會包含該元件的所呈現內容。The Parent component's rendered <div> contains extra="5" when passed through the additional attribute because the attributes are processed right to left (last to first):

<div extra="5" />

在下列範例中,和的順序 extra @attributes 會在 Child 元件的中反轉 <div>In the following example, the order of extra and @attributes is reversed in the Child component's <div>:

ParentComponent.razor:ParentComponent.razor:

<ChildComponent extra="10" />

ChildComponent.razor:ChildComponent.razor:

<div extra="5" @attributes="AdditionalAttributes" />

[Parameter(CaptureUnmatchedValues = true)]
public IDictionary<string, object> AdditionalAttributes { get; set; }

<div> Parent extra="10" 當透過其他屬性傳遞時,元件中所呈現的會包含:The rendered <div> in the Parent component contains extra="10" when passed through the additional attribute:

<div extra="10" />

捕獲元件的參考Capture references to components

元件參考提供一個參考元件實例的方式,讓您可以將命令發出至該實例,例如 ShowResetComponent references provide a way to reference a component instance so that you can issue commands to that instance, such as Show or Reset. 若要捕獲元件參考:To capture a component reference:

  • @ref 屬性新增至子元件。Add an @ref attribute to the child component.
  • 使用與子元件相同的類型來定義欄位。Define a field with the same type as the child component.
<CustomLoginDialog @ref="loginDialog" ... />

@code {
    private CustomLoginDialog loginDialog;

    private void OnSomething()
    {
        loginDialog.Show();
    }
}

轉譯元件時,此 loginDialog 欄位會填入 MyLoginDialog 子元件實例。When the component is rendered, the loginDialog field is populated with the MyLoginDialog child component instance. 然後,您可以在元件實例上叫用 .NET 方法。You can then invoke .NET methods on the component instance.

重要

loginDialog變數只會在呈現元件之後填入,且其輸出會包含 MyLoginDialog 元素。The loginDialog variable is only populated after the component is rendered and its output includes the MyLoginDialog element. 在呈現元件之前,不需要參考任何專案。Until the component is rendered, there's nothing to reference.

若要在元件完成轉譯之後操作元件參考,請使用 OnAfterRenderAsyncOnAfterRender 方法To manipulate components references after the component has finished rendering, use the OnAfterRenderAsync or OnAfterRender methods.

若要在事件處理常式中使用參考變數,請使用 lambda 運算式,或在 OnAfterRenderAsyncOnAfterRender 方法中指派事件處理常式委派。To use a reference variable with an event handler, use a lambda expression or assign the event handler delegate in the OnAfterRenderAsync or OnAfterRender methods. 這可確保在指派事件處理常式之前,會先指派參考變數。This ensures that the reference variable is assigned before the event handler is assigned.

<button type="button" 
    @onclick="@(() => loginDialog.DoSomething())">Do Something</button>

<MyLoginDialog @ref="loginDialog" ... />

@code {
    private MyLoginDialog loginDialog;
}

若要參考迴圈中的元件,請參閱 (dotnet/aspnetcore #13358) ,捕捉多個類似子元件的參考 To reference components in a loop, see Capture references to multiple similar child-components (dotnet/aspnetcore #13358).

雖然捕捉元件參考使用類似的語法來 捕捉元素參考,但它並不是 JavaScript interop 功能。While capturing component references use a similar syntax to capturing element references, it isn't a JavaScript interop feature. 元件參考不會傳遞至 JavaScript 程式碼。Component references aren't passed to JavaScript code. 元件參考僅適用于 .NET 程式碼。Component references are only used in .NET code.

注意

請勿 使用元件 參考來改變子元件的狀態。Do not use component references to mutate the state of child components. 相反地,請使用一般宣告式參數將資料傳遞給子元件。Instead, use normal declarative parameters to pass data to child components. 使用一般宣告式參數會導致子元件自動 rerender 正確的時間。Use of normal declarative parameters result in child components that rerender at the correct times automatically.

同步處理內容Synchronization context

Blazor 使用同步處理內容 (SynchronizationContext) 來強制執行單一邏輯執行緒。Blazor uses a synchronization context (SynchronizationContext) to enforce a single logical thread of execution. 元件的 生命週期方法 和所引發的任何事件回呼 Blazor 都會在同步處理內容上執行。A component's lifecycle methods and any event callbacks that are raised by Blazor are executed on the synchronization context.

Blazor Server的同步處理內容會嘗試模擬單一執行緒環境,使它與瀏覽器中的 WebAssembly 模型緊密相符,也就是單一執行緒。Blazor Server's synchronization context attempts to emulate a single-threaded environment so that it closely matches the WebAssembly model in the browser, which is single threaded. 在任何給定的時間點,工作只會在一個執行緒上執行,以提供單一邏輯執行緒的印象。At any given point in time, work is performed on exactly one thread, giving the impression of a single logical thread. 不會同時執行兩個作業。No two operations execute concurrently.

避免執行緒封鎖呼叫Avoid thread-blocking calls

一般而言,請勿呼叫下列方法。Generally, don't call the following methods. 下列方法會封鎖執行緒,因此會封鎖應用程式繼續工作,直到基礎 Task 完成為止:The following methods block the thread and thus block the app from resuming work until the underlying Task is complete:

在外部叫用元件方法以更新狀態Invoke component methods externally to update state

在事件中,必須根據外來事件(例如計時器或其他通知)更新元件,然後使用 InvokeAsync 方法來分派至 Blazor 同步處理內容。In the event a component must be updated based on an external event, such as a timer or other notifications, use the InvokeAsync method, which dispatches to Blazor's synchronization context. 例如,假設有一個可通知任何已更新狀態之接聽元件的通知程式 服務For example, consider a notifier service that can notify any listening component of the updated state:

public class NotifierService
{
    // Can be called from anywhere
    public async Task Update(string key, int value)
    {
        if (Notify != null)
        {
            await Notify.Invoke(key, value);
        }
    }

    public event Func<string, int, Task> Notify;
}

註冊 NotifierServiceRegister the NotifierService:

  • 在中 Blazor WebAssembly ,以 singleton 的形式註冊服務 Program.MainIn Blazor WebAssembly, register the service as singleton in Program.Main:

    builder.Services.AddSingleton<NotifierService>();
    
  • 在中 Blazor Server ,註冊服務的範圍如下 Startup.ConfigureServicesIn Blazor Server, register the service as scoped in Startup.ConfigureServices:

    services.AddScoped<NotifierService>();
    

使用 NotifierService 更新元件:Use the NotifierService to update a component:

@page "/"
@inject NotifierService Notifier
@implements IDisposable

<p>Last update: @lastNotification.key = @lastNotification.value</p>

@code {
    private (string key, int value) lastNotification;

    protected override void OnInitialized()
    {
        Notifier.Notify += OnNotify;
    }

    public async Task OnNotify(string key, int value)
    {
        await InvokeAsync(() =>
        {
            lastNotification = (key, value);
            StateHasChanged();
        });
    }

    public void Dispose()
    {
        Notifier.Notify -= OnNotify;
    }
}

在上述範例中,會在的 NotifierService 同步處理內容之外叫用元件的 OnNotify 方法 Blazor 。In the preceding example, NotifierService invokes the component's OnNotify method outside of Blazor's synchronization context. InvokeAsync 用來切換至正確的內容,並將轉譯排入佇列。InvokeAsync is used to switch to the correct context and queue a render.

使用 @ 金鑰來控制元素和元件的保留Use @key to control the preservation of elements and components

當轉譯元素或元件的清單,以及後續變更的元素或元件時, Blazor 的比較演算法必須決定可以保留先前的元素或元件,以及模型物件應該如何對應至這些專案或元件。When rendering a list of elements or components and the elements or components subsequently change, Blazor's diffing algorithm must decide which of the previous elements or components can be retained and how model objects should map to them. 一般來說,此程式是自動的,而且可以忽略,但在某些情況下,您可能會想要控制此進程。Normally, this process is automatic and can be ignored, but there are cases where you may want to control the process.

請考慮下列範例:Consider the following example:

@foreach (var person in People)
{
    <DetailsEditor Details="@person.Details" />
}

@code {
    [Parameter]
    public IEnumerable<Person> People { get; set; }
}

集合的內容 People 可能會隨著插入、刪除或重新排序的專案而變更。The contents of the People collection may change with inserted, deleted, or re-ordered entries. 元件轉譯中時, <DetailsEditor> 元件可能會變更以接收不同的 Details 參數值。When the component rerenders, the <DetailsEditor> component may change to receive different Details parameter values. 這可能會導致比預期更複雜的轉譯資料流程。This may cause more complex rerendering than expected. 在某些情況下,轉譯資料流程可能會導致可見的行為差異,例如遺失的元素焦點。In some cases, rerendering can lead to visible behavior differences, such as lost element focus.

您可以使用指示詞屬性來控制對應進程 @keyThe mapping process can be controlled with the @key directive attribute. @key 使比較演算法保證根據索引鍵的值來保留元素或元件:@key causes the diffing algorithm to guarantee preservation of elements or components based on the key's value:

@foreach (var person in People)
{
    <DetailsEditor @key="person" Details="@person.Details" />
}

@code {
    [Parameter]
    public IEnumerable<Person> People { get; set; }
}

People 集合變更時,比較演算法會保留 <DetailsEditor> 實例和實例之間的關聯 personWhen the People collection changes, the diffing algorithm retains the association between <DetailsEditor> instances and person instances:

  • 如果 Person 從清單中刪除 People ,則只 <DetailsEditor> 會從 UI 中移除對應的實例。If a Person is deleted from the People list, only the corresponding <DetailsEditor> instance is removed from the UI. 其他實例則保持不變。Other instances are left unchanged.
  • 如果 Person 插入清單中的某個位置,就 <DetailsEditor> 會在該對應位置插入一個新的實例。If a Person is inserted at some position in the list, one new <DetailsEditor> instance is inserted at that corresponding position. 其他實例則保持不變。Other instances are left unchanged.
  • 如果 Person 重新排序專案,則 <DetailsEditor> 會保留對應的實例,並在 UI 中重新排序。If Person entries are re-ordered, the corresponding <DetailsEditor> instances are preserved and re-ordered in the UI.

在某些情況下,使用可將 @key 轉譯資料流程的複雜性降至最低,並避免變更 DOM 的可設定狀態部分(例如焦點位置)。In some scenarios, use of @key minimizes the complexity of rerendering and avoids potential issues with stateful parts of the DOM changing, such as focus position.

重要

索引鍵是每個容器元素或元件的本機密鑰。Keys are local to each container element or component. 索引鍵不會在檔之間進行全域比較。Keys aren't compared globally across the document.

使用金鑰的時機 @When to use @key

一般來說,在轉譯清單時使用 @key (例如,在 foreach 區塊) 中,以及定義的適當值 @keyTypically, it makes sense to use @key whenever a list is rendered (for example, in a foreach block) and a suitable value exists to define the @key.

當物件變更時,您也可以使用 @key 防止 Blazor 保留元素或元件子樹:You can also use @key to prevent Blazor from preserving an element or component subtree when an object changes:

<div @key="currentPerson">
    ... content that depends on currentPerson ...
</div>

如果 @currentPerson 有變更,屬性指示詞會 @key 強制 Blazor 捨棄整個 <div> 和其子系,並使用新的元素和元件重建 UI 內的子樹。If @currentPerson changes, the @key attribute directive forces Blazor to discard the entire <div> and its descendants and rebuild the subtree within the UI with new elements and components. 如果您需要保證在變更時不會保留任何 UI 狀態,這會很有用 @currentPersonThis can be useful if you need to guarantee that no UI state is preserved when @currentPerson changes.

何時不使用 @ 金鑰When not to use @key

與進行比較時,會產生效能成本 @keyThere's a performance cost when diffing with @key. 效能成本不大,但只會指定 @key 控制元素或元件保留規則是否能讓應用程式受益。The performance cost isn't large, but only specify @key if controlling the element or component preservation rules benefit the app.

即使 @key 未使用,也會盡可能 Blazor 保留子項目和元件實例。Even if @key isn't used, Blazor preserves child element and component instances as much as possible. 使用的唯一優點 @key 是控制模型實例 如何 對應至保留的元件實例,而不是選取對應的比較演算法。The only advantage to using @key is control over how model instances are mapped to the preserved component instances, instead of the diffing algorithm selecting the mapping.

用於索引鍵的值 @What values to use for @key

一般來說,提供下列其中一種值的意義 @keyGenerally, it makes sense to supply one of the following kinds of value for @key:

  • 例如, Person 如先前範例所示的 (模型物件實例) 。Model object instances (for example, a Person instance as in the earlier example). 這可確保根據物件參考相等來保留。This ensures preservation based on object reference equality.
  • 唯一識別碼 (例如,、或) 類型的主 int 鍵值 string GuidUnique identifiers (for example, primary key values of type int, string, or Guid).

確定用於的值 @key 不會衝突。Ensure that values used for @key don't clash. 如果在相同的父元素內偵測到衝突值,則會擲回例外狀況, Blazor 因為它無法將舊的元素或元件以決定性的方式對應至新的元素或元件。If clashing values are detected within the same parent element, Blazor throws an exception because it can't deterministically map old elements or components to new elements or components. 只使用相異的值,例如物件實例或主鍵值。Only use distinct values, such as object instances or primary key values.

覆寫的參數Overwritten parameters

當父元件轉譯中時,會提供新的參數值(通常會覆寫現有的參數值)。New parameter values are supplied, typically overwriting existing ones, when the parent component rerenders.

請考慮下列 Expander 元件:Consider the following Expander component that:

  • 轉譯子內容。Renders child content.
  • 切換使用元件參數顯示子內容。Toggles showing child content with a component parameter.
<div @onclick="@Toggle" class="card bg-light mb-3" style="width:30rem">
    <div class="card-body">
        <h2 class="card-title">Toggle (<code>Expanded</code> = @Expanded)</h2>

        @if (Expanded)
        {
            <p class="card-text">@ChildContent</p>
        }
    </div>
</div>

@code {
    [Parameter]
    public bool Expanded { get; set; }

    [Parameter]
    public RenderFragment ChildContent { get; set; }

    private void Toggle()
    {
        Expanded = !Expanded;
    }
}

Expander元件會新增至可能呼叫的父元件 StateHasChangedThe Expander component is added to a parent component that may call StateHasChanged:

@page "/expander"

<Expander Expanded="true">
    Expander 1 content
</Expander>

<Expander Expanded="true" />

<button @onclick="StateHasChanged">
    Call StateHasChanged
</button>

一開始, Expander 當元件的屬性切換時,元件會獨立運作 ExpandedInitially, the Expander components behave independently when their Expanded properties are toggled. 子元件會如預期般維護其狀態。The child components maintain their states as expected. StateHasChanged 在父系中呼叫時, Expanded 第一個子元件的參數會重設回其初始值 (true) 。When StateHasChanged is called in the parent, the Expanded parameter of the first child component is reset back to its initial value (true). 第二個 Expander 元件的 Expanded 值不會重設,因為不會在第二個元件中轉譯任何子內容。The second Expander component's Expanded value isn't reset because no child content is rendered in the second component.

若要在先前的案例中維持狀態,請使用元件中的 私用欄位 Expander 來維持其切換狀態。To maintain state in the preceding scenario, use a private field in the Expander component to maintain its toggled state.

下列修訂的 Expander 元件:The following revised Expander component:

  • 接受 Expanded 來自父系的元件參數值。Accepts the Expanded component parameter value from the parent.
  • 將元件參數值指派給private field expanded OnInitialized 事件中 () 的私用欄位。Assigns the component parameter value to a private field (expanded) in the OnInitialized event.
  • 使用私用欄位來維護其內部切換狀態。Uses the private field to maintain its internal toggle state.
<div @onclick="@Toggle" class="card bg-light mb-3" style="width:30rem">
    <div class="card-body">
        <h2 class="card-title">Toggle (<code>expanded</code> = @expanded)</h2>

        @if (expanded)
        {
            <p class="card-text">@ChildContent</p>
        }
    </div>
</div>

@code {
    private bool expanded;

    [Parameter]
    public bool Expanded { get; set; }

    [Parameter]
    public RenderFragment ChildContent { get; set; }

    protected override void OnInitialized()
    {
        expanded = Expanded;
    }

    private void Toggle()
    {
        expanded = !expanded;
    }
}

套用屬性Apply an attribute

您可以使用指示詞將屬性套用至 Razor 元件 @attributeAttributes can be applied to Razor components with the @attribute directive. 下列範例會將 [Authorize] 屬性套用至元件類別:The following example applies the [Authorize] attribute to the component class:

@page "/"
@attribute [Authorize]

條件式 HTML 元素屬性Conditional HTML element attributes

HTML 元素屬性是根據 .NET 值以有條件的形式呈現。HTML element attributes are conditionally rendered based on the .NET value. 如果值為 falsenull ,則不會呈現屬性。If the value is false or null, the attribute isn't rendered. 如果值為 true ,則會將屬性轉譯為最小化。If the value is true, the attribute is rendered minimized.

在下列範例中, IsCompleted 判斷 checked 是否在專案的標記中轉譯:In the following example, IsCompleted determines if checked is rendered in the element's markup:

<input type="checkbox" checked="@IsCompleted" />

@code {
    [Parameter]
    public bool IsCompleted { get; set; }
}

如果 IsCompletedtrue ,則會將此核取方塊轉譯為:If IsCompleted is true, the check box is rendered as:

<input type="checkbox" checked />

如果 IsCompletedfalse ,則會將此核取方塊轉譯為:If IsCompleted is false, the check box is rendered as:

<input type="checkbox" />

如需詳細資訊,請參閱ASP.NET Core 的 razor 語法參考For more information, see ASP.NET Core 的 razor 語法參考.

警告

當 .NET 類型為時,某些 HTML 屬性(例如 aria-pressed )無法正常運作 boolSome HTML attributes, such as aria-pressed, don't function properly when the .NET type is a bool. 在這些情況下,請使用型別, string 而不是 boolIn those cases, use a string type instead of a bool.

原始 HTMLRaw HTML

字串通常會使用 DOM 文位元組點來呈現,這表示它們所包含的標記會被忽略,並視為常值文字。Strings are normally rendered using DOM text nodes, which means that any markup they may contain is ignored and treated as literal text. 若要轉譯原始 HTML,請將 HTML 內容包裝成 MarkupString 值。To render raw HTML, wrap the HTML content in a MarkupString value. 值會剖析為 HTML 或 SVG 並插入 DOM 中。The value is parsed as HTML or SVG and inserted into the DOM.

警告

轉譯從任何未受信任來源所建立的原始 HTML 會有 安全性風險 ,應予以避免!Rendering raw HTML constructed from any untrusted source is a security risk and should be avoided!

下列範例顯示如何使用 MarkupString 型別,將靜態 HTML 內容的區塊加入至元件的轉譯輸出:The following example shows using the MarkupString type to add a block of static HTML content to the rendered output of a component:

@((MarkupString)myMarkup)

@code {
    private string myMarkup = 
        "<p class='markup'>This is a <em>markup string</em>.</p>";
}

Razor 範本Razor templates

您可以使用範本語法來定義轉譯片段 Razor 。Render fragments can be defined using Razor template syntax. Razor 範本是定義 UI 程式碼片段的方式,並採用下列格式:Razor templates are a way to define a UI snippet and assume the following format:

@<{HTML tag}>...</{HTML tag}>

下列範例說明如何 RenderFragment RenderFragment<TValue> 在元件中直接指定和值,以及轉譯範本。The following example illustrates how to specify RenderFragment and RenderFragment<TValue> values and render templates directly in a component. 轉譯片段也可以做為引數傳遞至樣板 化元件Render fragments can also be passed as arguments to templated components.

@timeTemplate

@petTemplate(new Pet { Name = "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; }
    }
}

上述程式碼的呈現輸出:Rendered output of the preceding code:

<p>The time is 10/04/2018 01:26:52.</p>

<p>Pet: Rex</p>

靜態資產Static assets

Blazor遵循 ASP.NET Core 應用程式將靜態資產放置於專案 web root (wwwroot) 資料夾底下的慣例。Blazor follows the convention of ASP.NET Core apps placing static assets under the project's web root (wwwroot) folder.

使用基底相對路徑 (/) 參考靜態資產的 web 根目錄。Use a base-relative path (/) to refer to the web root for a static asset. 在下列範例中, logo.png 實際上是位於資料夾中 {PROJECT ROOT}/wwwroot/imagesIn the following example, logo.png is physically located in the {PROJECT ROOT}/wwwroot/images folder:

<img alt="Company logo" src="/images/logo.png" />

Razor 元件 () 支援波狀符號斜線標記法 ~/Razor components do not support tilde-slash notation (~/).

如需設定應用程式基底路徑的詳細資訊,請參閱 裝載和部署 ASP.NET Core BlazorFor information on setting an app's base path, see 裝載和部署 ASP.NET Core Blazor.

元件中不支援標記協助程式Tag Helpers aren't supported in components

Tag Helpers) (的元件中不支援 Razor .razorTag Helpers aren't supported in Razor components (.razor files). 若要在中提供標籤協助程式的功能,請使用與標籤協助程式 Blazor 相同的功能建立元件,並改為使用該元件。To provide Tag Helper-like functionality in Blazor, create a component with the same functionality as the Tag Helper and use the component instead.

可擴充的向量圖形 (SVG) 影像Scalable Vector Graphics (SVG) images

由於 Blazor 呈現 HTML、瀏覽器支援的影像,包括可擴充的向量圖形 (SVG) 影像 (.svg) )可透過 <img> 標記支援:Since Blazor renders HTML, browser-supported images, including Scalable Vector Graphics (SVG) images (.svg), are supported via the <img> tag:

<img alt="Example image" src="some-image.svg" />

同樣地, () 的樣式表單檔案的 CSS 規則中支援 SVG 影像 .cssSimilarly, SVG images are supported in the CSS rules of a stylesheet file (.css):

.my-element {
    background-image: url("some-image.svg");
}

不過,並非所有案例都支援內嵌 SVG 標記。However, inline SVG markup isn't supported in all scenarios. 如果您將 <svg> 標記直接放入元件檔 (.razor) ,則支援基本映射轉譯,但目前尚不支援許多先進的案例。If you place an <svg> tag directly into a component file (.razor), basic image rendering is supported but many advanced scenarios aren't yet supported. 例如, <use> 目前未遵守標記,且 @bind 無法與某些 SVG 標記一起使用。For example, <use> tags aren't currently respected, and @bind can't be used with some SVG tags. 如需詳細資訊,請參閱 Blazor (dotnet/aspnetcore 中的 SVG 支援 #18271) For more information, see SVG support in Blazor (dotnet/aspnetcore #18271).

其他資源Additional resources