在 Blazor 應用程式中共用資料

已完成

Blazor 有幾種方式可在元件之間共用資訊。 您可以使用元件參數或串聯參數,將值從父元件傳送至子元件。 AppState 模式是另一種方法,可用來儲存值並從應用程式中的任何元件存取值。

假設您正在建置新的披薩外送網站。 多個披薩應該以相同的方式顯示在首頁上。 您想要藉由轉譯每個披薩的子元件來顯示披薩。 現在,您想要將識別碼傳遞至該子元件,以決定其會顯示的披薩。 您也想要在多個元件上儲存並顯示值,以顯示今天的披薩銷售總數。

在本單元中,您將了解可用來在兩個以上的 Blazor 元件之間共用值的三種不同技術。

使用元件參數來與其他元件共用資訊

在 Blazor Web 應用程式中,每個元件都會轉譯一部分的 HTML。 有些元件會轉譯整個頁面,有些元件則只會轉譯較小的標記片段,例如資料表、表單或單一控制項。 如果您的元件只會轉譯一段標記,您就必須將其作為父元件內的子元件來使用。 子元件也可以是在其內轉譯的其他較小元件的父元件。 子元件也稱為巢狀元件。

在這個有父元件和子元件的階層中,您可以使用元件參數讓其彼此共用資訊。 在子元件上定義這些參數,然後在父元件中設定其值。 例如,如果您有顯示披薩圖片的子元件,則可以使用元件參數來傳遞披薩識別碼。 子元件會透過識別碼查閱披薩,並取得圖片和其他資料。 如果您想要顯示許多不同的披薩,就可以在相同的父頁面上多次使用此子元件,並向每個子元件傳遞不同的識別碼。

首先,請在子元件中定義元件參數。 其會定義為 C# 公用屬性,並使用 [Parameter] 屬性加以裝飾:

<h2>New Pizza: @PizzaName</h2>

<p>@PizzaDescription</p>

@code {
    [Parameter]
    public string PizzaName { get; set; }
    
    [Parameter]
    public string PizzaDescription { get; set; } = "The best pizza you've ever tasted."
}

因為元件參數是子元件的成員,所以您可以使用 Blazor 的保留 @ 符號,並於後面加上其名稱,而在 HTML 中轉譯這些參數。 此外,上述程式碼會指定 PizzaDescription 參數的預設值。 如果父元件未傳遞值,則會轉譯此值。 否則,會由從父元件傳遞的值加以覆寫。

您也可以在專案中使用自訂類別來作為元件參數。 請考慮用來描述配料的這個類別:

public class PizzaTopping
{
    public string Name { get; set; }
    public string Ingredients { get; set; }
}

您可以像參數值一樣地使用該類別作為元件參數,使用點語法來存取該類別的個別屬性:

<h2>New Topping: @Topping.Name</h2>

<p>Ingredients: @Topping.Ingredients</p>

@code {
    [Parameter]
    public PizzaTopping Topping { get; set; }
}

在父元件中,使用子元件標籤的屬性來設定參數值。 簡單的元件可以直接設定。 透過以自訂類別為基礎的參數,您會使用內嵌 C# 程式碼,來建立該類別的新執行個體並設定其值:

@page "/pizzas-toppings"

<h1>Our Latest Pizzas and Topping</h1>

<Pizza PizzaName="Hawaiian" PizzaDescription="The one with pineapple" />

<PizzaTopping Topping="@(new PizzaTopping() { Name = "Chilli Sauce", Ingredients = "Three kinds of chilli." })" />

使用串聯參數來共用資訊

當您想要將值傳遞給元件的直屬子系時,元件參數會正常運作。 當您的階層很深,有不斷拓展的子系時,情況就會變得麻煩。 系統不會自動將元件參數從上階元件傳遞給下階元件,也不會在階層中一路傳遞下去。 為了簡潔地處理這個問題,Blazor 納入了串聯參數。 當您在元件中設定串聯參數的值時,系統會將其值自動提供給位於任何深度的所有子元件。

在父元件中,使用 <CascadingValue> 標籤會指定要串聯至所有子元件的資訊。 此標籤會實作為內建 Blazor 元件。 在該標籤內轉譯的任何元件都能夠存取該值。

@page "/specialoffers"

<h1>Special Offers</h1>

<CascadingValue Name="DealName" Value="Throwback Thursday">
    <!-- Any descendant component rendered here will be able to access the cascading value. -->
</CascadingValue>

在子元件中,您可以使用元件成員並為其裝飾上 [CascadingParameter] 屬性,而能夠存取串聯值。

<h2>Deal: @DealName</h2>

@code {
    [CascadingParameter(Name="DealName")]
    private string DealName { get; set; }
}

因此在本範例中,<h2> 標籤會有 Deal: Throwback Thursday 內容,因為該串聯值由上階元件設定。

注意

就元件參數而言,如果您有更複雜的需求,則可以將物件作為串聯參數來進行傳遞。

在上述範例中,串聯值會由父元件中的 Name 屬性加以識別,且此屬性會與 [CascadingParameter] 屬性中的 Name 值進行比對。 您可以選擇性地省略這些名稱,在此情況下,屬性會依類型進行比對。 當您只有一個該型別的參數時,省略名稱的效果很好。 如果您想要串聯兩個不同的字串值,則必須使用參數名稱來避免任何歧異。

使用 AppState 來共用資訊

另一種在不同元件之間共用資訊的方法是使用 AppState 模式。 您可以建立類別來定義您想要儲存的屬性,並將該類別註冊為範圍服務。 在您想要設定或使用 AppState 值的任何元件中,您可以插入服務,然後存取其屬性。 不同於元件參數和串聯參數,AppState 中的值可供應用程式中的所有元件使用,甚至可供儲存了值但並非元件子系的元件使用。

例如,請考慮這個儲存了銷售相關數據的類別:

public class PizzaSalesState
{
    public int PizzasSoldToday { get; set; }
}

您會將此類別新增為 Program.cs 檔案中的範圍服務:

...
// Add services to the container
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();

// Add the AppState class
builder.Services.AddScoped<PizzaSalesState>();
...

現在,在您想要設定或擷取 AppState 值的任何元件中,您可以插入此類別,然後存取屬性:

@page "/"
@inject PizzaSalesState SalesState

<h1>Welcome to Blazing Pizzas</h1>

<p>Today, we've sold this many pizzas: @SalesState.PizzasSoldToday</p>

<button @onclick="IncrementSales">Buy a Pizza</button>

@code {
    private void IncrementSales()
    {
        SalesState.PizzasSoldToday++;
    }
}

注意

此程式碼會實作計數器,當使用者選取按鈕時便會遞增值,情況與 Blazor 教學課程 - 建置您的第一個 Blazor 應用程式中的範例極為類似。 差別在於,在此情況下,因為我們已將計數器的值儲存到 AppState 範圍服務中,所以計數會跨頁面載入持續下去,而且其他使用者可以看到。

在下一個單元中,您會自己試試!

檢定您的知識

1.

Blazor 元件可以使用兩種類型的參數來接收輸入。 是哪兩種?

2.

AppState 可以使用下列哪一個陳述式向服務定位器進行註冊?