Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Poznámka:
Toto není nejnovější verze tohoto článku. Aktuální verzi najdete ve verzi .NET 10 tohoto článku.
Varování
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální vydání najdete v článku verze .NET 9.
Tento článek vysvětluje, jak používat virtualizaci komponent v aplikacích ASP.NET Core Blazor .
Virtualizace
Zlepšete vnímaný výkon vykreslování komponent pomocí integrované podpory virtualizace frameworku s komponentou Blazor. 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.
Použijte komponentu Virtualize<TItem>, když:
- 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. Nezobrazené 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:
-
allFlightsje kolekce leteckých letů. - Komponenta
FlightSummaryzobrazuje podrobnosti o jednotlivých letech. - Atribut
@keydirektivy zachovává vztah každéFlightSummarykomponenty k jejímu vykreslenému letu prostřednictvímFlightIdletu.
<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é zaznamenávají 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
allFlightsjako pevný zdroj položek pro 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ždý let pomocí parametru
Context. V následujícím příkladu seflightpoužívá jako kontext, který poskytuje přístup k členům každého letu.
<div style="height:500px;overflow-y:scroll">
<Virtualize Items="allFlights" Context="flight">
<FlightSummary @key="flight.FlightId" Details="@flight.Summary" />
</Virtualize>
</div>
Pokud kontext není zadán pomocí parametru Context, použijte hodnotu context ve vzoru obsahu položky pro přístup k členům jednotlivých letů.
<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 část záznamů z externího rozhraní API, která odpovídá aktuálně viditelné oblasti, včetně přesahu, když se použije
ItemsProvidermí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.
- Jeden nebo více Razor komponentů.
- Směs komponent HTML/Razor a Razor.
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 ve formě ItemsProviderResult<TItem> spolu s počtem všech 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, při nastavování parametrů komponenty za běhu se vyvolá InvalidOperationException.
Následující příklad načte zaměstnance z objektu EmployeeService, který není zobrazen. 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 negenerické kolekce, takže delegát poskytovatele 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í RefreshDataAsyncnení obvykle nutné volat Items .
RefreshDataAsync
Virtualize<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 je RefreshDataAsync aktivováno odděleně od úlohy nebo události na pozadí, například v následujícím delegátu ForecastUpdated, zavolejte StateHasChanged pro aktualizaci uživatelského rozhraní na konci této ú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> .
-
StateHasChangedje volán k opětovnému vykreslení 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 ??= [];
}
@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 ??= [];
}
Změňte metodu OnInitialized lambda tak, aby se zobrazily řetězce zobrazení komponenty:
protected override void OnInitialized() =>
stringList ??= [ "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í. Použijte ItemSize, abyste předem poskytli přesnou velikost položky, což pomůže k dosažení přesného počátečního výkonu vykreslení a zajistí 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.
Počet překrývání
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í počet přehledů z výchozího počtu 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, abyste zařadili opětovné vyhodnocení a znovuvykreslení komponenty do fronty. 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í fokusovatelné. 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 tabindex hodnoty -1, 0nebo jiných hodnot naleznete v tématu tabindex.
Pokročilé styly a detekce rolová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 obsahem jsou vloženy prvky mezery div. Slouží ke dvěma účelům:
- Aby se před a za vaším obsahem nastavil posun, způsobí to, že aktuálně viditelné položky se zobrazí na korektním umístění v rozsahu posouvání, a samotný rozsah posouvání aby představoval 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 ovládat značku elementu HTML mezerníku, najdete v části Ovládání názvu značky elementu mezerníku dále v tomto článku.
Prvky interně používají Intersection Observer ke přijímání 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.
Oddělovače i řádky obsahu se vykreslují v jednom svislém stohu, přičemž každá položka vyplňuje celou vodorovnou šířku. V typických případech
Virtualizefunguje s prvkydiv. 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
displays libovolnou z následujících hodnot:-
block(výchozí hodnota pro adiv). -
table-row-group(výchozí hodnota pro atbody). -
flexsflex-directionnastavenou nacolumn. Zajistěte, aby se okamžití podřízené elementy komponenty Virtualize<TItem> nezmenšily podle pravidel flex. Přidejte například.mycontainer > div { flex-shrink: 0 }.
-
- Stylování řádků obsahu vyžaduje, aby
displaymělo jednu z následujících hodnot:-
block(výchozí hodnota pro adiv). -
table-row(výchozí hodnota pro atr).
-
- Nepoužívejte CSS k narušení rozložení prvků pomocí mezer. Prvky mezery mají
displayhodnotublock, s výjimkou případů, kdy je nadřazeným skupina řádků tabulky, v takovém případě mají výchozí hodnotutable-row. Nepokoušejte se ovlivnit šířku nebo výšku prvku mezerníku, například tím, že jim přiřadíte ohraničení nebocontentpseudo-prvky.
- Stylování kontejneru posouvání vyžaduje
Jakýkoli přístup, který zastaví vykreslování mezer a obsahových prvků jako jediného svislého sloupce, nebo způsobí, že se položky obsahu budou lišit ve výšce, brání komponentě Virtualize<TItem> ve správné funkčnosti.
Virtualizace na kořenové úrovni
Komponenta Virtualize<TItem> podporuje použití samotného dokumentu jako kořene posouvání, jako alternativu k použití nějakého jiného prvku 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řene posouvání, jako alternativu k použití nějakého jiného prvku s overflow-y: scroll. Pokud používáte dokument jako kořen posouvání, vyhněte se stylování prvků <html> nebo <body> pomocí overflow-y: scroll, protože by to způsobilo, že pozorovatel průsečíku zachází s celou posuvnou výškou stránky jako s viditelnou oblastí, místo aby takto pracoval pouze s 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řene posouvání s 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, buď se vyhněte stylování <html>/<body> prvků s overflow-y: scroll, 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řene posouvání, jako alternativu k použití nějakého jiného prvku s overflow-y: scroll. Pokud dokument používáte jako kořen posouvání, vyhněte se stylování prvků <html> nebo <body> pomocí overflow-y: scroll, protože to způsobí, že celá posouvatelná výška stránky bude považována za viditelnou oblast, a ne jen za 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řene posouvání s 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, buď se vyhněte stylování <html>/<body> prvků s overflow-y: scroll, 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>
Ovládání názvu značky elementu mezera
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 mezery pro virtualizaci. 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 prvky html jsou stylovány s body. 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