virtualizace komponent ASP.NET Core Razor
Poznámka:
Toto není nejnovější verze tohoto článku. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Upozorňující
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Důležité
Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.
Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Tento článek vysvětluje, jak používat virtualizaci komponent v aplikacích ASP.NET Core Blazor .
Virtualizace
Zlepšení vnímaného výkonu vykreslování komponent pomocí Blazor integrované podpory virtualizace architektury s komponentou Virtualize<TItem> . Virtualizace je technika omezení vykreslování uživatelského rozhraní jenom na aktuálně viditelné části. Například virtualizace je užitečná, když aplikace musí vykreslit dlouhý seznam položek a v libovolném okamžiku se vyžaduje jenom podmnožina položek.
Komponentu použijte v následujících Virtualize<TItem> případech:
- Vykreslení sady datových položek ve smyčce
- Většina položek není viditelná kvůli posouvání.
- Vykreslené položky mají stejnou velikost.
Když se uživatel v seznamu položek komponenty posune na libovolný bod Virtualize<TItem> , komponenta vypočítá viditelné položky, které se mají zobrazit. Nezoznané položky se nevykreslují.
Bez virtualizace může typický seznam použít smyčku jazyka C# foreach
k vykreslení každé položky v seznamu. V následujícím příkladu:
allFlights
je kolekce letadel.- Komponenta
FlightSummary
zobrazuje podrobnosti o jednotlivých testovacích verzích. - Atribut
@key
direktivy zachovává vztah každéFlightSummary
komponenty k jeho vykreslené letu letFlightId
let .
<div style="height:500px;overflow-y:scroll">
@foreach (var flight in allFlights)
{
<FlightSummary @key="flight.FlightId" Details="@flight.Summary" />
}
</div>
Pokud kolekce obsahuje tisíce letů, vykreslování letů trvá dlouhou dobu a uživatelé zaznamenat znatelnou prodlevu uživatelského rozhraní. Většina letů spadá mimo výšku <div>
prvku, takže většina z nich není vidět.
Místo vykreslení celého seznamu letů najednou nahraďte foreach
smyčku v předchozím příkladu komponentou Virtualize<TItem> :
Zadejte
allFlights
jako zdroj pevné položky do Virtualize<TItem>.Items. Komponenta Virtualize<TItem> vykresluje pouze aktuálně viditelné lety.Pokud kolekce, která není obecná, poskytuje položky, například kolekci DataRow, postupujte podle pokynů v oddílu delegáta zprostředkovatele položky a zadejte položky.
Zadejte kontext pro každou testovací verzi s parametrem
Context
. V následujícím příkladuflight
se používá jako kontext, který poskytuje přístup k členům každé testovací verze.
<div style="height:500px;overflow-y:scroll">
<Virtualize Items="allFlights" Context="flight">
<FlightSummary @key="flight.FlightId" Details="@flight.Summary" />
</Virtualize>
</div>
Pokud není zadaný kontext s parametrem Context
, použijte hodnotu context
v šabloně obsahu položky pro přístup ke členům jednotlivých testovacích verzí:
<div style="height:500px;overflow-y:scroll">
<Virtualize Items="allFlights">
<FlightSummary @key="context.FlightId" Details="@context.Summary" />
</Virtualize>
</div>
Komponenta Virtualize<TItem> :
- Vypočítá počet položek, které se mají vykreslit na základě výšky kontejneru a velikosti vykreslovaných položek.
- Přepočítá a znovu vygeneruje položky při posouvání uživatelem.
- Načte pouze řez záznamů z externího rozhraní API, které odpovídá aktuálně viditelné oblasti, včetně přeskenu, při
ItemsProvider
použití místoItems
(viz oddíl delegáta zprostředkovatele položky).
Obsah položky pro komponentu Virtualize<TItem> může zahrnovat:
- Prostý kód HTML a Razor kód, jak ukazuje předchozí příklad.
- Jedna nebo více Razor součástí.
- Kombinace HTML/Razor a Razor komponent.
Delegát zprostředkovatele položek
Pokud nechcete načíst všechny položky do paměti nebo kolekce není obecná ICollection<T>, můžete zadat metodu delegáta zprostředkovatele položek na parametr komponenty Virtualize<TItem>.ItemsProvider , který asynchronně načte požadované položky na vyžádání. V následujícím příkladu LoadEmployees
metoda poskytuje položky komponentě Virtualize<TItem> :
<Virtualize Context="employee" ItemsProvider="LoadEmployees">
<p>
@employee.FirstName @employee.LastName has the
job title of @employee.JobTitle.
</p>
</Virtualize>
Zprostředkovatel položek obdrží hodnotu ItemsProviderRequest, která určuje požadovaný počet položek počínaje konkrétním počátečním indexem. Zprostředkovatel položek pak načte požadované položky z databáze nebo jiné služby a vrátí je jako ItemsProviderResult<TItem> počet celkových položek. Poskytovatel položek se může rozhodnout načíst položky s jednotlivými požadavky nebo je uložit do mezipaměti, aby byly snadno dostupné.
Komponenta Virtualize<TItem> může přijímat pouze jeden zdroj položek ze svých parametrů, takže se nepokoušejte současně používat zprostředkovatele položek a přiřazovat kolekci Items
. Pokud jsou oba přiřazeny, vyvolá se při InvalidOperationException nastavení parametrů komponenty za běhu.
Následující příklad načte zaměstnance z objektu EmployeeService
(není zobrazeno). Pole totalEmployees
by obvykle bylo přiřazeno voláním metody ve stejné službě (například EmployeesService.GetEmployeesCountAsync
) jinde, například během inicializace součástí.
private async ValueTask<ItemsProviderResult<Employee>> LoadEmployees(
ItemsProviderRequest request)
{
var numEmployees = Math.Min(request.Count, totalEmployees - request.StartIndex);
var employees = await EmployeesService.GetEmployeesAsync(request.StartIndex,
numEmployees, request.CancellationToken);
return new ItemsProviderResult<Employee>(employees, totalEmployees);
}
V následujícím příkladu je kolekce DataRow ne generické kolekce, takže delegát zprostředkovatele položek se používá pro virtualizaci:
<Virtualize Context="row" ItemsProvider="GetRows">
...
</Virtualize>
@code{
...
private ValueTask<ItemsProviderResult<DataRow>> GetRows(ItemsProviderRequest request) =>
new(new ItemsProviderResult<DataRow>(
dataTable.Rows.OfType<DataRow>().Skip(request.StartIndex).Take(request.Count),
dataTable.Rows.Count));
}
Virtualize<TItem>.RefreshDataAsync dává komponentě pokyn, aby znovu požadovala data z jeho ItemsProvider. To je užitečné, když se změní externí data. Při použití Itemsnení obvykle nutné volat RefreshDataAsync .
RefreshDataAsyncVirtualize<TItem> aktualizuje data komponenty, aniž by to způsobilo opětovné obnovení. Pokud RefreshDataAsync je vyvolána z Blazor obslužné rutiny události nebo metody životního cyklu komponent, aktivace vykreslení není vyžadována, protože vykreslení se automaticky aktivuje na konci obslužné rutiny události nebo metody životního cyklu. Pokud RefreshDataAsync se aktivuje odděleně od úlohy nebo události na pozadí, například v následujícím ForecastUpdated
delegátu, volání StateHasChanged pro aktualizaci uživatelského rozhraní na konci úlohy nebo události na pozadí:
<Virtualize ... @ref="virtualizeComponent">
...
</Virtualize>
...
private Virtualize<FetchData>? virtualizeComponent;
protected override void OnInitialized()
{
WeatherForecastSource.ForecastUpdated += async () =>
{
await InvokeAsync(async () =>
{
await virtualizeComponent?.RefreshDataAsync();
StateHasChanged();
});
});
}
V předchozím příkladu:
- RefreshDataAsync je volána jako první pro získání nových dat pro komponentu Virtualize<TItem> .
StateHasChanged
je volána k opětovnému vyřazuje komponentu.
Zástupný symbol
Vzhledem k tomu, že vyžádání položek ze vzdáleného zdroje dat může nějakou dobu trvat, máte možnost vykreslit zástupný symbol s obsahem položky:
- Pomocí funkce (Placeholder
<Placeholder>...</Placeholder>
) zobrazte obsah, dokud nebudou data položky k dispozici. - Slouží Virtualize<TItem>.ItemContent k nastavení šablony položky pro seznam.
<Virtualize Context="employee" ItemsProvider="LoadEmployees">
<ItemContent>
<p>
@employee.FirstName @employee.LastName has the
job title of @employee.JobTitle.
</p>
</ItemContent>
<Placeholder>
<p>
Loading…
</p>
</Placeholder>
</Virtualize>
Prázdný obsah
Pomocí parametru EmptyContent můžete zadat obsah, pokud je komponenta načtena a Items je prázdná nebo ItemsProviderResult<TItem>.TotalItemCount je nula.
EmptyContent.razor
:
@page "/empty-content"
<PageTitle>Empty Content</PageTitle>
<h1>Empty Content Example</h1>
<Virtualize Items="stringList">
<ItemContent>
<p>
@context
</p>
</ItemContent>
<EmptyContent>
<p>
There are no strings to display.
</p>
</EmptyContent>
</Virtualize>
@code {
private List<string>? stringList;
protected override void OnInitialized() => stringList ??= new();
}
@page "/empty-content"
<PageTitle>Empty Content</PageTitle>
<h1>Empty Content Example</h1>
<Virtualize Items="stringList">
<ItemContent>
<p>
@context
</p>
</ItemContent>
<EmptyContent>
<p>
There are no strings to display.
</p>
</EmptyContent>
</Virtualize>
@code {
private List<string>? stringList;
protected override void OnInitialized() => stringList ??= new();
}
Změňte metodu OnInitialized
lambda tak, aby se zobrazily řetězce zobrazení komponenty:
protected override void OnInitialized() =>
stringList ??= new() { "Here's a string!", "Here's another string!" };
Velikost položky
Výšku každé položky v pixelech lze nastavit pomocí Virtualize<TItem>.ItemSize (výchozí hodnota: 50). Následující příklad změní výšku každé položky z výchozích 50 pixelů na 25 pixelů:
<Virtualize Context="employee" Items="employees" ItemSize="25">
...
</Virtualize>
Komponenta Virtualize<TItem> měří velikost vykreslování (výšku) jednotlivých položek po počátečním vykreslení. Umožňuje ItemSize předem poskytnout přesnou velikost položky, která vám pomůže s přesným počátečním výkonem vykreslení a zajistit správnou pozici posouvání pro opětovné načtení stránky. Pokud výchozí nastavení ItemSize způsobí, že se některé položky vykreslují mimo aktuálně viditelné zobrazení, aktivuje se druhý rerender. Aby bylo možné správně udržovat pozici posouvání prohlížeče ve virtualizovaném seznamu, musí být počáteční vykreslení správné. Pokud ne, uživatelé můžou zobrazit nesprávné položky.
Overscan count
Virtualize<TItem>.OverscanCount určuje, kolik dalších položek se vykresluje před a za viditelnou oblastí. Toto nastavení pomáhá snížit frekvenci vykreslování během posouvání. Vyšší hodnoty ale mají za následek více prvků vykreslených na stránce (výchozí hodnota: 3). Následující příklad změní přehledat počet z výchozích tří položek na čtyři položky:
<Virtualize Context="employee" Items="employees" OverscanCount="4">
...
</Virtualize>
Změny stavu
Při provádění změn položek vykreslovaných komponentou Virtualize<TItem> volejte StateHasChanged opětovné vyhodnocení a reendering součásti. Další informace najdete v tématu Vykreslování komponent ASP.NET Core Razor.
Podpora posouvání pomocí klávesnice
Pokud chcete uživatelům umožnit posouvání virtualizovaného obsahu pomocí klávesnice, ujistěte se, že jsou virtualizované prvky nebo samotný kontejner posouvání fokus. Pokud tento krok neuděláte, posouvání pomocí klávesnice nefunguje v prohlížečích založených na Chromiu.
Můžete například použít tabindex
atribut v kontejneru scroll:
<div style="height:500px; overflow-y:scroll" tabindex="-1">
<Virtualize Items="allFlights">
<div class="flight-info">...</div>
</Virtualize>
</div>
Další informace o významu hodnoty , nebo jiných hodnotách najdetetabindex
v dokumentaci k MDN. 0
-1
tabindex
Pokročilé styly a detekce posouvání
Komponenta Virtualize<TItem> je určena pouze pro podporu konkrétních mechanismů rozložení prvků. Abyste pochopili, která rozložení prvků fungují správně, vysvětluje následující část, jak Virtualize
zjistí, které prvky by měly být viditelné pro zobrazení na správném místě.
Pokud zdrojový kód vypadá takto:
<div style="height:500px; overflow-y:scroll" tabindex="-1">
<Virtualize Items="allFlights" ItemSize="100">
<div class="flight-info">Flight @context.Id</div>
</Virtualize>
</div>
Komponenta Virtualize<TItem> za běhu vykreslí strukturu DOM podobnou následující:
<div style="height:500px; overflow-y:scroll" tabindex="-1">
<div style="height:1100px"></div>
<div class="flight-info">Flight 12</div>
<div class="flight-info">Flight 13</div>
<div class="flight-info">Flight 14</div>
<div class="flight-info">Flight 15</div>
<div class="flight-info">Flight 16</div>
<div style="height:3400px"></div>
</div>
Skutečný počet vykreslených řádků a velikost mezerník se liší podle stylu a Items
velikosti kolekce. Všimněte si však, že před obsahem a za obsah se vloží mezerník div
. Slouží ke dvěma účelům:
- Pokud chcete poskytnout posun před a za obsahem, což způsobí, že se aktuálně viditelné položky zobrazí ve správném umístění v oblasti posouvání a samotné oblasti posouvání představující celkovou velikost veškerého obsahu.
- Pokud chcete zjistit, kdy se uživatel posunuje nad aktuální viditelnou oblast, což znamená, že se musí vykreslit jiný obsah.
Poznámka:
Informace o tom, jak řídit značku elementu HTML mezerníku, najdete v části Ovládací prvek název značky elementu mezerníku dále v tomto článku.
Prvky mezerník interně používají pozorovatel průniku k příjmu oznámení, když se stanou viditelnými. Virtualize
závisí na příjmu těchto událostí.
Virtualize
funguje za následujících podmínek:
Všechny vykreslené položky obsahu, včetně zástupného obsahu, mají stejnou výšku. To umožňuje vypočítat, který obsah odpovídá dané pozici posouvání, aniž byste nejdřív načítali každou datovou položku a vykreslili data do prvku MODELU DOM.
Mezerník i řádky obsahu se vykreslují v jednom svislém zásobníku s každou položkou, která vyplňuje celou vodorovnou šířku. V typických případech
Virtualize
použití pracuje sdiv
prvky. Pokud k vytvoření pokročilejšího rozložení používáte šablony stylů CSS, mějte na paměti následující požadavky:- Stylování kontejneru posouvání vyžaduje některou
display
z následujících hodnot:block
(výchozí hodnota pro adiv
).table-row-group
(výchozí hodnota pro atbody
).flex
sflex-direction
nastavenou nacolumn
hodnotu . Zajistěte, aby se okamžité podřízené položky Virtualize<TItem> komponenty nezmenšily v rámci pravidel flex. Přidejte například.mycontainer > div { flex-shrink: 0 }
.
- Stylování řádků obsahu vyžaduje
display
jednu z následujících hodnot:block
(výchozí hodnota pro adiv
).table-row
(výchozí hodnota pro atr
).
- Nepoužívejte šablony stylů CSS k narušení rozložení prvků mezerník. Prvky mezery mají
display
hodnotublock
, s výjimkou případů, kdy nadřazený je skupina řádků tabulky, v takovém případě jsou výchozítable-row
. Nepokoušejte se ovlivnit šířku nebo výšku prvku mezerníku, včetně jejich příčin, že mají ohraničení nebocontent
pseudo-prvky.
- Stylování kontejneru posouvání vyžaduje některou
Jakýkoli přístup, který zastaví vykreslování prvků mezer a obsahu jako jednoho svislého zásobníku nebo způsobí, že se položky obsahu budou lišit ve výšce, brání správnému Virtualize<TItem> fungování komponenty.
Virtualizace na kořenové úrovni
Komponenta Virtualize<TItem> podporuje použití samotného dokumentu jako kořen posouvání, jako alternativu k tomu, že má nějaký jiný prvek s overflow-y: scroll
. V následujícím příkladu <html>
<body>
jsou prvky stylovány v komponentě s overflow-y: scroll
:
<HeadContent>
<style>
html, body { overflow-y: scroll }
</style>
</HeadContent>
Komponenta Virtualize<TItem> podporuje použití samotného dokumentu jako kořen posouvání, jako alternativu k tomu, že má nějaký jiný prvek s overflow-y: scroll
. Pokud dokument používáte jako kořen posouvání, vyhněte se stylům <html>
nebo prvků, overflow-y: scroll
protože pozorovatel průsečíku zachází s úplnou výškou stránky jako s viditelnou oblastí, a ne jenom s <body>
oblastí zobrazení okna.
Tento problém můžete reprodukovat vytvořením velkého virtualizovaného seznamu (například 100 000 položek) a pokusem o použití dokumentu jako kořenového adresáře html { overflow-y: scroll }
ve stylech CSS stránky. I když může někdy správně fungovat, prohlížeč se pokusí vykreslit všech 100 000 položek alespoň jednou při spuštění vykreslování, což může způsobit uzamčení karty prohlížeče.
Chcete-li tento problém vyřešit před vydáním rozhraní .NET 7, vyhněte se stylům <html>
/<body>
prvků s overflow-y: scroll
alternativním přístupem nebo použijte alternativní přístup. V následujícím příkladu je výška <html>
prvku nastavená na více než 100 % výšky oblasti zobrazení:
<HeadContent>
<style>
html { min-height: calc(100vh + 0.3px) }
</style>
</HeadContent>
Komponenta Virtualize<TItem> podporuje použití samotného dokumentu jako kořen posouvání, jako alternativu k tomu, že má nějaký jiný prvek s overflow-y: scroll
. Pokud dokument používáte jako kořen posouvání, vyhněte se stylům <html>
nebo <body>
prvků, overflow-y: scroll
protože způsobí, že úplná výška stránky bude považována za viditelnou oblast, a ne jenom oblast zobrazení okna.
Tento problém můžete reprodukovat vytvořením velkého virtualizovaného seznamu (například 100 000 položek) a pokusem o použití dokumentu jako kořenového adresáře html { overflow-y: scroll }
ve stylech CSS stránky. I když může někdy správně fungovat, prohlížeč se pokusí vykreslit všech 100 000 položek alespoň jednou při spuštění vykreslování, což může způsobit uzamčení karty prohlížeče.
Chcete-li tento problém vyřešit před vydáním rozhraní .NET 7, vyhněte se stylům <html>
/<body>
prvků s overflow-y: scroll
alternativním přístupem nebo použijte alternativní přístup. V následujícím příkladu je výška <html>
prvku nastavená na více než 100 % výšky oblasti zobrazení:
<style>
html { min-height: calc(100vh + 0.3px) }
</style>
Řízení názvu značky elementu mezerníku
Pokud je komponenta Virtualize<TItem> umístěna uvnitř elementu, který vyžaduje konkrétní název podřízené značky, SpacerElement umožňuje získat nebo nastavit název značky mezerníku virtualizace. Výchozí hodnota je div
. V následujícím příkladu se komponenta Virtualize<TItem> vykresluje uvnitř elementu těla tabulky (tbody
), takže příslušný podřízený prvek pro řádek tabulky (tr
) je nastaven jako mezerník.
VirtualizedTable.razor
:
@page "/virtualized-table"
<PageTitle>Virtualized Table</PageTitle>
<HeadContent>
<style>
html, body {
overflow-y: scroll
}
</style>
</HeadContent>
<h1>Virtualized Table Example</h1>
<table id="virtualized-table">
<thead style="position: sticky; top: 0; background-color: silver">
<tr>
<th>Item</th>
<th>Another column</th>
</tr>
</thead>
<tbody>
<Virtualize Items="fixedItems" ItemSize="30" SpacerElement="tr">
<tr @key="context" style="height: 30px;" id="row-@context">
<td>Item @context</td>
<td>Another value</td>
</tr>
</Virtualize>
</tbody>
</table>
@code {
private List<int> fixedItems = Enumerable.Range(0, 1000).ToList();
}
V předchozím příkladu se kořen dokumentu používá jako kontejner posouvání, takže html
prvky jsou body
stylovány pomocí overflow-y: scroll
. Další informace naleznete v následujících zdrojích:
- Oddíl virtualizace na kořenové úrovni
- Řízení hlavního obsahu v aplikacích ASP.NET Core Blazor