składniki szablonów ASP.NET Core Blazor
Uwaga
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Ważne
Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.
Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Autor: Robert Haken
W tym artykule wyjaśniono, jak szablony składników mogą akceptować co najmniej jeden szablon interfejsu użytkownika jako parametry, które następnie mogą być używane jako część logiki renderowania składnika.
Składniki z szablonami
Składniki szablonowe to składniki, które odbierają co najmniej jeden szablon interfejsu użytkownika jako parametry, które mogą być używane w logice renderowania składnika. Za pomocą szablonowych składników można tworzyć składniki wyższego poziomu, które są bardziej wielokrotnego użytku. Oto kilka przykładów:
- Składnik tabeli, który umożliwia użytkownikowi określanie szablonów nagłówka, wierszy i stopki tabeli.
- Składnik listy, który umożliwia użytkownikowi określenie szablonu do renderowania elementów na liście.
- Składnik paska nawigacyjnego, który umożliwia użytkownikowi określenie szablonu dla początkowej zawartości i linków nawigacji.
Składnik szablonu jest definiowany przez określenie co najmniej jednego parametru składnika typu RenderFragment lub RenderFragment<TValue>. Fragment renderowania reprezentuje segment interfejsu użytkownika do renderowania. RenderFragment<TValue> przyjmuje parametr typu, który można określić po wywołaniu fragmentu renderowania.
Uwaga
Aby uzyskać więcej informacji na temat RenderFragmentprogramu , zobacz składniki ASP.NET CoreRazor.
Często składniki szablonów są typowo typizowane, jak pokazano w poniższym TemplatedNavBar
składniku (TemplatedNavBar.razor
). Typ ogólny () w<T>
poniższym przykładzie służy do renderowania IReadOnlyList<T> wartości, co w tym przypadku jest listą zwierząt domowych dla składnika, który wyświetla pasek nawigacyjny z linkami do składnika szczegółów zwierząt domowych.
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;
}
W przypadku korzystania ze składnika szablonu parametry szablonu można określić przy użyciu elementów podrzędnych, które są zgodne z nazwami parametrów. W poniższym przykładzie <StartContent>...</StartContent>
i <ItemTemplate>...</ItemTemplate>
podaj RenderFragment<TValue> szablony dla StartContent
i ItemTemplate
składnika TemplatedNavBar
.
Context
Określ atrybut w elemencie składnika, jeśli chcesz określić nazwę parametru zawartości niejawnej zawartości podrzędnej (bez opakowującego elementu podrzędnego). W poniższym przykładzie atrybut pojawia Context
się w elemecie TemplatedNavBar
i ma zastosowanie do wszystkich RenderFragment<TValue> parametrów szablonu.
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; }
}
}
Alternatywnie można zmienić nazwę parametru przy użyciu atrybutu Context
w elemecie podrzędnym RenderFragment<TValue> . W poniższym przykładzie parametr Context
jest ustawiony ItemTemplate
zamiast 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; }
}
}
Argumenty składników typu RenderFragment<TValue> mają niejawny parametr o nazwie context
, którego można użyć. W poniższym przykładzie Context
nie ustawiono wartości . @context.{PROPERTY}
dostarcza wartości zwierząt domowych do szablonu, gdzie {PROPERTY}
jest właściwością 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; }
}
}
W przypadku korzystania ze składników typowych ogólnych parametr typu jest wywnioskowany, jeśli to możliwe. Można jednak jawnie określić typ z atrybutem, który ma nazwę zgodną z parametrem typu, który znajduje się TItem
w poprzednim przykładzie:
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; }
}
}
W przykładzie podanym w składniku TemplatedNavBar
(TemplatedNavBar.razor
) przyjęto założenie, że Items
kolekcja nie zmienia się po początkowym renderowaniu lub jeśli ulegnie zmianie, utrzymywanie stanu składników/elementów używanych w ItemTemplate
programie nie jest konieczne. W przypadku składników szablonów, w których nie można przewidzieć takiego użycia, zobacz sekcję Zachowaj relacje z @key
.
Zachowywanie relacji za pomocą polecenia @key
Składniki szablonowe są często używane do renderowania kolekcji elementów, takich jak tabele lub listy. W takich ogólnych scenariuszach nie można założyć, że użytkownik będzie unikać składników stanowych/elementów w definicji szablonu elementu lub że nie będzie dodatkowych zmian Items
w kolekcji. W przypadku takich szablonowych składników należy zachować relacje z atrybutem @key
dyrektywy.
Uwaga
Aby uzyskać więcej informacji na temat atrybutu dyrektywy, zobacz Zachowywanie @key
relacji elementu, składnika i modelu w programie ASP.NET CoreBlazor.
Poniższy TableTemplate
składnik (TableTemplate.razor
) demonstruje szablonowy składnik, który zachowuje relacje z elementem @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;
}
Rozważmy następujący Pets5
składnik (Pets5.razor
), który pokazuje znaczenie kluczy danych w celu zachowania relacji modelu. W składniku każda iteracja dodawania zwierzaka w OnAfterRenderAsync
wyniku Blazor rerendering TableTemplate
składnika.
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; }
}
}
Ten pokaz umożliwia:
- Wybierz spośród
<input>
kilku renderowanych wierszy tabeli. - Badanie zachowania fokusu strony w miarę automatycznego wzrostu kolekcji zwierząt domowych.
Bez używania atrybutu @key
dyrektywy w składniku TableTemplate
fokus strony pozostaje na tej samej pozycji indeksu (wiersza) tabeli, co powoduje przesunięcie fokusu za każdym razem, gdy zwierzę jest dodawane. Aby to zademonstrować, usuń @key
atrybut i wartość dyrektywy, uruchom ponownie aplikację i spróbuj zmodyfikować wartość pola w miarę dodawania elementów.