ASP.NET Core Blazor 樣板化元件
注意
這不是這篇文章的最新版本。 如需目前的版本,請參閱 本文的 .NET 9 版本。
警告
不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支持原則。 如需目前的版本,請參閱 本文的 .NET 9 版本。
由 Robert Haken 提供
本文說明樣板化元件如何接受一或多個 UI 範本作為參數,然後將其用作元件轉譯邏輯的一部分。
樣板化元件
樣板化元件是接收一或多個 UI 範本作為參數的元件,可在元件的轉譯邏輯中使用。 藉由使用樣板化元件,您可建立更能重複使用的較高層級元件。 範例包含:
- 資料表元件,可讓使用者指定資料表頁首、資料列和頁尾的範本。
- 清單元件,可讓使用者指定範本來轉譯清單中的項目。
- 導覽列元件,可讓使用者指定開始內容和導覽連結的範本。
樣板化元件是藉由指定類型為 RenderFragment 或 RenderFragment<TValue> 的一或多個元件參數來定義。 轉譯片段代表要轉譯的 UI 區段。 RenderFragment<TValue> 採用可在叫用轉譯片段時指定的型別參數。
注意
如需 RenderFragment 的詳細資訊,請參閱 ASP.NET Core Razor 元件。
樣板化元件通常會為泛型類型,如下列 TemplatedNavBar
元件 (TemplatedNavBar.razor
) 示範。 下列範例中的泛型類型 (<T>
) 可用來轉譯 IReadOnlyList<T> 值,在此案例中,這是顯示具有寵物詳細資料元件連結之導覽列之元件的寵物清單。
TemplatedNavBar.razor
:
@typeparam TItem
<nav class="navbar navbar-expand navbar-light bg-light">
<div class="container justify-content-start">
@StartContent
<div class="navbar-nav">
@foreach (var item in Items)
{
@ItemTemplate(item)
}
</div>
</div>
</nav>
@code {
[Parameter]
public RenderFragment? StartContent { get; set; }
[Parameter, EditorRequired]
public RenderFragment<TItem> ItemTemplate { get; set; } = default!;
[Parameter, EditorRequired]
public IReadOnlyList<TItem> Items { get; set; } = default!;
}
@typeparam TItem
<nav class="navbar navbar-expand navbar-light bg-light">
<div class="container justify-content-start">
@StartContent
<div class="navbar-nav">
@foreach (var item in Items)
{
@ItemTemplate(item)
}
</div>
</div>
</nav>
@code {
[Parameter]
public RenderFragment? StartContent { get; set; }
[Parameter, EditorRequired]
public RenderFragment<TItem> ItemTemplate { get; set; } = default!;
[Parameter, EditorRequired]
public IReadOnlyList<TItem> Items { get; set; } = default!;
}
@typeparam TItem
<nav class="navbar navbar-expand navbar-light bg-light">
<div class="container justify-content-start">
@StartContent
<div class="navbar-nav">
@foreach (var item in Items)
{
@ItemTemplate(item)
}
</div>
</div>
</nav>
@code {
[Parameter]
public RenderFragment? StartContent { get; set; }
[Parameter, EditorRequired]
public RenderFragment<TItem> ItemTemplate { get; set; } = default!;
[Parameter, EditorRequired]
public IReadOnlyList<TItem> Items { get; set; } = default!;
}
@typeparam TItem
<nav class="navbar navbar-expand navbar-light bg-light">
<div class="container justify-content-start">
@StartContent
<div class="navbar-nav">
@foreach (var item in Items)
{
@ItemTemplate(item)
}
</div>
</div>
</nav>
@code {
[Parameter]
public RenderFragment? StartContent { get; set; }
[Parameter, EditorRequired]
public RenderFragment<TItem> ItemTemplate { get; set; } = default!;
[Parameter, EditorRequired]
public IReadOnlyList<TItem> Items { get; set; } = default!;
}
@typeparam TItem
<nav class="navbar navbar-expand navbar-light bg-light">
<div class="container justify-content-start">
@StartContent
<div class="navbar-nav">
@foreach (var item in Items)
{
@ItemTemplate(item)
}
</div>
</div>
</nav>
@code {
[Parameter]
public RenderFragment StartContent { get; set; }
[Parameter]
public RenderFragment<TItem> ItemTemplate { get; set; } = default;
[Parameter]
public IReadOnlyList<TItem> Items { get; set; } = default;
}
@typeparam TItem
<nav class="navbar navbar-expand navbar-light bg-light">
<div class="container justify-content-start">
@StartContent
<div class="navbar-nav">
@foreach (var item in Items)
{
@ItemTemplate(item)
}
</div>
</div>
</nav>
@code {
[Parameter]
public RenderFragment StartContent { get; set; }
[Parameter]
public RenderFragment<TItem> ItemTemplate { get; set; } = default;
[Parameter]
public IReadOnlyList<TItem> Items { get; set; } = default;
}
使用樣板化元件時,可以使用符合參數名稱的子項目來指定範本參數。 在下列範例中,<StartContent>...</StartContent>
和 <ItemTemplate>...</ItemTemplate>
為 TemplatedNavBar
元件的 StartContent
和 ItemTemplate
提供 RenderFragment<TValue> 範本。
當您想要指定隱含子系內容的內容參數名稱時,請在元件元素上指定 Context
屬性 (不含任何包裝子矽元素)。 在下列範例中,Context
屬性會出現在 TemplatedNavBar
元素上,並套用至所有 RenderFragment<TValue> 範本參數。
Pets1.razor
:
@page "/pets-1"
<PageTitle>Pets 1</PageTitle>
<h1>Pets Example 1</h1>
<TemplatedNavBar Items="pets" Context="pet">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-1")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-1"
<PageTitle>Pets 1</PageTitle>
<h1>Pets Example 1</h1>
<TemplatedNavBar Items="pets" Context="pet">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-1")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-1"
<PageTitle>Pets 1</PageTitle>
<h1>Pets Example 1</h1>
<TemplatedNavBar Items="pets" Context="pet">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-1")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-1"
<PageTitle>Pets 1</PageTitle>
<h1>Pets Example 1</h1>
<TemplatedNavBar Items="pets" Context="pet">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-1"
<h1>Pets Example 1</h1>
<TemplatedNavBar Items="pets" Context="pet">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string Name { get; set; }
}
}
@page "/pets-1"
<h1>Pets Example 1</h1>
<TemplatedNavBar Items="pets" Context="pet">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string Name { get; set; }
}
}
或者,您可使用 RenderFragment<TValue> 子系元素上的 Context
屬性來變更參數名稱。 在下列範例中,Context
是設定於 ItemTemplate
,而不是 TemplatedNavBar
。
Pets2.razor
:
@page "/pets-2"
<PageTitle>Pets 2</PageTitle>
<h1>Pets Example 2</h1>
<TemplatedNavBar Items="pets">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate Context="pet">
<NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-2")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-2"
<PageTitle>Pets 2</PageTitle>
<h1>Pets Example 2</h1>
<TemplatedNavBar Items="pets">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate Context="pet">
<NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-2")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-2"
<PageTitle>Pets 2</PageTitle>
<h1>Pets Example 2</h1>
<TemplatedNavBar Items="pets">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate Context="pet">
<NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-2")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-2"
<PageTitle>Pets 2</PageTitle>
<h1>Pets Example 2</h1>
<TemplatedNavBar Items="pets">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate Context="pet">
<NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-2"
<h1>Pets Example 2</h1>
<TemplatedNavBar Items="pets">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate Context="pet">
<NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string Name { get; set; }
}
}
@page "/pets-2"
<h1>Pets Example 2</h1>
<TemplatedNavBar Items="pets">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate Context="pet">
<NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string Name { get; set; }
}
}
RenderFragment<TValue> 類型的元件引數具有名為 context
的隱含參數可供使用。 在下列範例中,未設定 Context
。 @context.{PROPERTY}
提供寵物值給範本,其中 {PROPERTY}
是 Pet
屬性:
Pets3.razor
:
@page "/pets-3"
<PageTitle>Pets 3</PageTitle>
<h1>Pets Example 3</h1>
<TemplatedNavBar Items="pets">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{context.PetId}?ReturnUrl=%2Fpets-3")" class="nav-link">
@context.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-3"
<PageTitle>Pets 3</PageTitle>
<h1>Pets Example 3</h1>
<TemplatedNavBar Items="pets">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{context.PetId}?ReturnUrl=%2Fpets-3")" class="nav-link">
@context.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-3"
<PageTitle>Pets 3</PageTitle>
<h1>Pets Example 3</h1>
<TemplatedNavBar Items="pets">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{context.PetId}?ReturnUrl=%2Fpets-3")" class="nav-link">
@context.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-3"
<PageTitle>Pets 3</PageTitle>
<h1>Pets Example 3</h1>
<TemplatedNavBar Items="pets">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{context.PetId}")" class="nav-link">
@context.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-3"
<h1>Pets Example 3</h1>
<TemplatedNavBar Items="pets">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{context.PetId}")" class="nav-link">
@context.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string Name { get; set; }
}
}
@page "/pets-3"
<h1>Pets Example 3</h1>
<TemplatedNavBar Items="pets">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{context.PetId}")" class="nav-link">
@context.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string Name { get; set; }
}
}
使用泛型類型的元件時,可能的話會推斷類型參數。 不過,您可使用名稱符合類型參數的屬性來明確指定類型,這就是上述範例中的 TItem
:
Pets4.razor
:
@page "/pets-4"
<PageTitle>Pets 4</PageTitle>
<h1>Pets Example 4</h1>
<TemplatedNavBar Items="pets" Context="pet" TItem="Pet">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-4")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 2, Name = "Mr. Bigglesworth" },
new Pet { PetId = 4, Name = "Salem Saberhagen" },
new Pet { PetId = 7, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-4"
<PageTitle>Pets 4</PageTitle>
<h1>Pets Example 4</h1>
<TemplatedNavBar Items="pets" Context="pet" TItem="Pet">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-4")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 2, Name = "Mr. Bigglesworth" },
new Pet { PetId = 4, Name = "Salem Saberhagen" },
new Pet { PetId = 7, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-4"
<PageTitle>Pets 4</PageTitle>
<h1>Pets Example 4</h1>
<TemplatedNavBar Items="pets" Context="pet" TItem="Pet">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{pet.PetId}?ReturnUrl=%2Fpets-4")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 2, Name = "Mr. Bigglesworth" },
new Pet { PetId = 4, Name = "Salem Saberhagen" },
new Pet { PetId = 7, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-4"
<PageTitle>Pets 4</PageTitle>
<h1>Pets Example 4</h1>
<TemplatedNavBar Items="pets" Context="pet" TItem="Pet">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 2, Name = "Mr. Bigglesworth" },
new Pet { PetId = 4, Name = "Salem Saberhagen" },
new Pet { PetId = 7, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-4"
<h1>Pets Example 4</h1>
<TemplatedNavBar Items="pets" Context="pet" TItem="Pet">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 2, Name = "Mr. Bigglesworth" },
new Pet { PetId = 4, Name = "Salem Saberhagen" },
new Pet { PetId = 7, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string Name { get; set; }
}
}
@page "/pets-4"
<h1>Pets Example 4</h1>
<TemplatedNavBar Items="pets" Context="pet" TItem="Pet">
<StartContent>
<a href="/" class="navbar-brand">PetsApp</a>
</StartContent>
<ItemTemplate>
<NavLink href="@($"/pet-detail/{pet.PetId}")" class="nav-link">
@pet.Name
</NavLink>
</ItemTemplate>
</TemplatedNavBar>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 2, Name = "Mr. Bigglesworth" },
new Pet { PetId = 4, Name = "Salem Saberhagen" },
new Pet { PetId = 7, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string Name { get; set; }
}
}
TemplatedNavBar
元件 (TemplatedNavBar.razor
) 中提供的範例假設初始轉譯之後,Items
集合不會變更;或者,如果確實變更,則不需要維護 ItemTemplate
中使用的元件/元素狀態。 如需無法預期這類使用方式的樣板化元件,請參閱保留與 @key
的關聯性一節。
使用 @key
保留關聯性
範本化元件通常用來轉譯項目的集合,例如資料表或清單。 在這類一般情況下,我們無法假設使用者會避免項目範本定義中的具狀態元件/元素,或不會對 Items
集合進行其他變更。 針對這類範本元件,必須保留與 @key
指示詞屬性的關聯性。
注意
如需 @key
指示詞屬性的詳細資訊,請參閱在 ASP.NET Core Blazor 中保留元素、元件和模型關聯性。
下列 TableTemplate
元件 (TableTemplate.razor
) 示範範本元件,該元件會保留與 @key
的關聯性。
TableTemplate.razor
:
@typeparam TItem
<table class="table">
<thead>
<tr>@TableHeader</tr>
</thead>
<tbody>
@foreach (var item in Items)
{
<tr @key="@item">@RowTemplate(item)</tr>
}
</tbody>
</table>
@code {
[Parameter]
public RenderFragment? TableHeader { get; set; }
[Parameter, EditorRequired]
public RenderFragment<TItem> RowTemplate { get; set; } = default!;
[Parameter, EditorRequired]
public IReadOnlyList<TItem> Items { get; set; } = default!;
}
@typeparam TItem
<table class="table">
<thead>
<tr>@TableHeader</tr>
</thead>
<tbody>
@foreach (var item in Items)
{
<tr @key="@item">@RowTemplate(item)</tr>
}
</tbody>
</table>
@code {
[Parameter]
public RenderFragment? TableHeader { get; set; }
[Parameter, EditorRequired]
public RenderFragment<TItem> RowTemplate { get; set; } = default!;
[Parameter, EditorRequired]
public IReadOnlyList<TItem> Items { get; set; } = default!;
}
@typeparam TItem
<table class="table">
<thead>
<tr>@TableHeader</tr>
</thead>
<tbody>
@foreach (var item in Items)
{
<tr @key="@item">@RowTemplate(item)</tr>
}
</tbody>
</table>
@code {
[Parameter]
public RenderFragment? TableHeader { get; set; }
[Parameter, EditorRequired]
public RenderFragment<TItem> RowTemplate { get; set; } = default!;
[Parameter, EditorRequired]
public IReadOnlyList<TItem> Items { get; set; } = default!;
}
@typeparam TItem
<table class="table">
<thead>
<tr>@TableHeader</tr>
</thead>
<tbody>
@foreach (var item in Items)
{
<tr @key="@item">@RowTemplate(item)</tr>
}
</tbody>
</table>
@code {
[Parameter]
public RenderFragment? TableHeader { get; set; }
[Parameter, EditorRequired]
public RenderFragment<TItem> RowTemplate { get; set; } = default!;
[Parameter, EditorRequired]
public IReadOnlyList<TItem> Items { get; set; } = default!;
}
@typeparam TItem
<table class="table">
<thead>
<tr>@TableHeader</tr>
</thead>
<tbody>
@foreach (var item in Items)
{
<tr @key="@item">@RowTemplate(item)</tr>
}
</tbody>
</table>
@code {
[Parameter]
public RenderFragment TableHeader { get; set; }
[Parameter]
public RenderFragment<TItem> RowTemplate { get; set; } = default;
[Parameter]
public IReadOnlyList<TItem> Items { get; set; } = default;
}
@typeparam TItem
<table class="table">
<thead>
<tr>@TableHeader</tr>
</thead>
<tbody>
@foreach (var item in Items)
{
<tr @key="@item">@RowTemplate(item)</tr>
}
</tbody>
</table>
@code {
[Parameter]
public RenderFragment TableHeader { get; set; }
[Parameter]
public RenderFragment<TItem> RowTemplate { get; set; } = default;
[Parameter]
public IReadOnlyList<TItem> Items { get; set; } = default;
}
請考慮下列 Pets5
元件 (Pets5.razor
),其示範鍵入資料以保留模型關聯性的重要性。 在元件中,每個在 OnAfterRenderAsync
中新增寵物的反覆項目都會使 Blazor 重新呈現 TableTemplate
元件。
Pets5.razor
:
@page "/pets-5"
<PageTitle>Pets 5</PageTitle>
<h1>Pets Example 5</h1>
<TableTemplate Items="pets" Context="pet">
<TableHeader>
<th>ID</th>
<th>Name</th>
</TableHeader>
<RowTemplate>
<td><input value="@pet.PetId" /></td>
<td><input value="@pet.Name" /></td>
</RowTemplate>
</TableTemplate>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
protected override async Task OnAfterRenderAsync(bool firstRender)
{
// Insert new pet every 5 seconds
if (pets.Count < 10)
{
await Task.Delay(5000);
pets.Insert(0, new Pet() { PetId = pets.Count + 1, Name = "<new pet>" });
StateHasChanged();
}
}
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-5"
<PageTitle>Pets 5</PageTitle>
<h1>Pets Example 5</h1>
<TableTemplate Items="pets" Context="pet">
<TableHeader>
<th>ID</th>
<th>Name</th>
</TableHeader>
<RowTemplate>
<td><input value="@pet.PetId" /></td>
<td><input value="@pet.Name" /></td>
</RowTemplate>
</TableTemplate>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
protected override async Task OnAfterRenderAsync(bool firstRender)
{
// Insert new pet every 5 seconds
if (pets.Count < 10)
{
await Task.Delay(5000);
pets.Insert(0, new Pet() { PetId = pets.Count + 1, Name = "<new pet>" });
StateHasChanged();
}
}
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-5"
<PageTitle>Pets 5</PageTitle>
<h1>Pets Example 5</h1>
<TableTemplate Items="pets" Context="pet">
<TableHeader>
<th>ID</th>
<th>Name</th>
</TableHeader>
<RowTemplate>
<td><input value="@pet.PetId" /></td>
<td><input value="@pet.Name" /></td>
</RowTemplate>
</TableTemplate>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
protected override async Task OnAfterRenderAsync(bool firstRender)
{
// Insert new pet every 5 seconds
if (pets.Count < 10)
{
await Task.Delay(5000);
pets.Insert(0, new Pet() { PetId = pets.Count + 1, Name = "<new pet>" });
StateHasChanged();
}
}
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-5"
<PageTitle>Pets 5</PageTitle>
<h1>Pets Example 5</h1>
<TableTemplate Items="pets" Context="pet">
<TableHeader>
<th>ID</th>
<th>Name</th>
</TableHeader>
<RowTemplate>
<td><input value="@pet.PetId" /></td>
<td><input value="@pet.Name" /></td>
</RowTemplate>
</TableTemplate>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
protected override async Task OnAfterRenderAsync(bool firstRender)
{
// Insert new pet every 5 seconds
if (pets.Count < 10)
{
await Task.Delay(5000);
pets.Insert(0, new Pet() { PetId = pets.Count + 1, Name = "<new pet>" });
StateHasChanged();
}
}
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}
@page "/pets-5"
<h1>Pets Example 5</h1>
<TableTemplate Items="pets" Context="pet">
<TableHeader>
<th>ID</th>
<th>Name</th>
</TableHeader>
<RowTemplate>
<td><input value="@pet.PetId" /></td>
<td><input value="@pet.Name" /></td>
</RowTemplate>
</TableTemplate>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
protected override async Task OnAfterRenderAsync(bool firstRender)
{
// Insert new pet every 5 seconds
if (pets.Count < 10)
{
await Task.Delay(5000);
pets.Insert(0, new Pet() { PetId = pets.Count + 1, Name = "<new pet>" });
StateHasChanged();
}
}
private class Pet
{
public int PetId { get; set; }
public string Name { get; set; }
}
}
@page "/pets-5"
<h1>Pets Example 5</h1>
<TableTemplate Items="pets" Context="pet">
<TableHeader>
<th>ID</th>
<th>Name</th>
</TableHeader>
<RowTemplate>
<td><input value="@pet.PetId" /></td>
<td><input value="@pet.Name" /></td>
</RowTemplate>
</TableTemplate>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 1, Name = "Mr. Bigglesworth" },
new Pet { PetId = 2, Name = "Salem Saberhagen" },
new Pet { PetId = 3, Name = "K-9" }
};
protected override async Task OnAfterRenderAsync(bool firstRender)
{
// Insert new pet every 5 seconds
if (pets.Count < 10)
{
await Task.Delay(5000);
pets.Insert(0, new Pet() { PetId = pets.Count + 1, Name = "<new pet>" });
StateHasChanged();
}
}
private class Pet
{
public int PetId { get; set; }
public string Name { get; set; }
}
}
此示範可讓您:
- 從數個已轉譯的資料列中選取
<input>
。 - 請研究頁面焦點在寵物集合自動成長的過程中會有怎樣的行為。
如果沒有在 TableTemplate
元件中使用 @key
指示詞屬性,頁面的焦點會維持在資料表的相同索引位置 (列) 上,導致每次新增寵物時焦點都會轉移。 若要示範這一點,請移除 @key
指示詞屬性和值、重新啟動應用程式,並嘗試在新增項目時修改域值。