wirtualizacja składników ASP.NET Core Razor
Uwaga
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.
Ostrzeżenie
Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz .NET i .NET Core Support Policy (Zasady obsługi platformy .NET Core). Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.
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ą, zapoznaj się z wersją tego artykułu platformy .NET 8.
W tym artykule wyjaśniono, jak używać wirtualizacji składników w aplikacjach ASP.NET Core Blazor .
Wirtualizacja
Zwiększ postrzeganą wydajność renderowania składników przy użyciu Blazor wbudowanej obsługi wirtualizacji platformy z składnikiem Virtualize<TItem> . Wirtualizacja to technika ograniczania renderowania interfejsu użytkownika tylko do części, które są obecnie widoczne. Na przykład wirtualizacja jest przydatna, gdy aplikacja musi renderować długą listę elementów, a tylko podzbiór elementów musi być widoczny w danym momencie.
Virtualize<TItem> Użyj składnika, gdy:
- Renderowanie zestawu elementów danych w pętli.
- Większość elementów nie jest widoczna z powodu przewijania.
- Renderowane elementy mają ten sam rozmiar.
Gdy użytkownik przewija dowolny punkt na Virtualize<TItem> liście elementów składnika, składnik oblicza widoczne elementy do pokazania. Niezaznaczone elementy nie są renderowane.
Bez wirtualizacji typowa lista może używać pętli języka C# foreach
do renderowania każdego elementu na liście. W poniższym przykładzie:
allFlights
jest kolekcją lotów samolotowych.- Składnik
FlightSummary
wyświetla szczegółowe informacje o każdym locie. - Atrybut
@key
dyrektywy zachowuje relację każdegoFlightSummary
składnika do jego renderowanego lotu przez lotFlightId
.
<div style="height:500px;overflow-y:scroll">
@foreach (var flight in allFlights)
{
<FlightSummary @key="flight.FlightId" Details="@flight.Summary" />
}
</div>
Jeśli kolekcja zawiera tysiące lotów, renderowanie lotów trwa długo, a użytkownicy doświadczają zauważalnego opóźnienia interfejsu użytkownika. Większość lotów wypada poza wysokość <div>
elementu, więc większość z nich nie jest widoczna.
Zamiast renderowania całej listy lotów jednocześnie, zastąp pętlę foreach
w poprzednim przykładzie składnikiem Virtualize<TItem> :
Określ
allFlights
jako źródło elementu stałego na Virtualize<TItem>.Items. Składnik renderuje Virtualize<TItem> tylko aktualnie widoczne loty.Jeśli kolekcja niegeneryczna dostarcza elementy, na przykład kolekcję DataRow, postępuj zgodnie ze wskazówkami w sekcji delegata dostawcy elementów, aby podać elementy.
Określ kontekst dla każdego lotu za pomocą parametru
Context
. W poniższym przykładzieflight
jest używany jako kontekst, który zapewnia dostęp do członków każdego lotu.
<div style="height:500px;overflow-y:scroll">
<Virtualize Items="allFlights" Context="flight">
<FlightSummary @key="flight.FlightId" Details="@flight.Summary" />
</Virtualize>
</div>
Jeśli kontekst nie jest określony za pomocą parametru Context
, użyj wartości context
w szablonie zawartości elementu, aby uzyskać dostęp do elementów członkowskich każdego pakietu:
<div style="height:500px;overflow-y:scroll">
<Virtualize Items="allFlights">
<FlightSummary @key="context.FlightId" Details="@context.Summary" />
</Virtualize>
</div>
Składnik Virtualize<TItem> :
- Oblicza liczbę elementów renderowanych na podstawie wysokości kontenera i rozmiaru renderowanych elementów.
- Ponownie oblicza i rerenders elementy podczas przewijania użytkownika.
- Pobiera tylko fragment rekordów z zewnętrznego interfejsu API, który odpowiada obecnie widocznemu regionie, w tym przeskanowania, gdy
ItemsProvider
jest używany zamiastItems
(zobacz sekcję Delegat dostawcy elementów).
Zawartość elementu dla Virtualize<TItem> składnika może obejmować:
- Zwykły kod HTML i Razor kod, jak pokazano w poprzednim przykładzie.
- Razor Co najmniej jeden składnik.
- Mieszanka kodu HTML/Razor i Razor składników.
Delegat dostawcy elementów
Jeśli nie chcesz załadować wszystkich elementów do pamięci lub kolekcja nie jest ogólną ICollection<T>metodą , możesz określić metodę delegata dostawcy elementów do parametru składnika Virtualize<TItem>.ItemsProvider , który asynchronicznie pobiera żądane elementy na żądanie. W poniższym przykładzie LoadEmployees
metoda udostępnia elementy składnikowi Virtualize<TItem> :
<Virtualize Context="employee" ItemsProvider="LoadEmployees">
<p>
@employee.FirstName @employee.LastName has the
job title of @employee.JobTitle.
</p>
</Virtualize>
Dostawca elementów otrzymuje element , który określa wymaganą ItemsProviderRequestliczbę elementów rozpoczynających się od określonego indeksu początkowego. Dostawca elementów pobiera następnie żądane elementy z bazy danych lub innej usługi i zwraca je jako wartość ItemsProviderResult<TItem> wraz z liczbą wszystkich elementów. Dostawca elementów może pobrać elementy z każdym żądaniem lub zapisać je w pamięci podręcznej, aby były łatwo dostępne.
Virtualize<TItem> Składnik może akceptować tylko jedno źródło elementu z jego parametrów, więc nie próbuj jednocześnie używać dostawcy elementów i przypisywać kolekcję do Items
elementu . Jeśli oba są przypisane, parametr jest zgłaszany, InvalidOperationException gdy parametry składnika są ustawiane w czasie wykonywania.
Poniższy przykład ładuje pracowników z elementu EmployeeService
(nie pokazano):
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);
}
W poniższym przykładzie kolekcja DataRow jest kolekcją niegeneryjną, więc delegat dostawcy elementów jest używany do wirtualizacji:
<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 instruuje składnik do ponownego pobierania danych z jego ItemsProviderelementu . Jest to przydatne, gdy dane zewnętrzne zmieniają się. Zwykle nie ma potrzeby wywoływania RefreshDataAsync w przypadku korzystania z polecenia Items.
RefreshDataAsyncVirtualize<TItem> aktualizuje dane składnika bez powodowania rerender. Jeśli RefreshDataAsync jest wywoływana z Blazor procedury obsługi zdarzeń lub metody cyklu życia składnika, wyzwalanie renderowania nie jest wymagane, ponieważ renderowanie jest automatycznie wyzwalane na końcu procedury obsługi zdarzeń lub metody cyklu życia. Jeśli RefreshDataAsync wyzwalane jest oddzielnie od zadania lub zdarzenia w tle, takiego jak w następującym ForecastUpdated
delegatu, wywołaj metodę StateHasChanged , aby zaktualizować interfejs użytkownika na końcu zadania lub zdarzenia w tle:
<Virtualize ... @ref="virtualizeComponent">
...
</Virtualize>
...
private Virtualize<FetchData>? virtualizeComponent;
protected override void OnInitialized()
{
WeatherForecastSource.ForecastUpdated += async () =>
{
await InvokeAsync(async () =>
{
await virtualizeComponent?.RefreshDataAsync();
StateHasChanged();
});
});
}
W powyższym przykładzie:
- RefreshDataAsync element jest wywoływany jako pierwszy w celu uzyskania nowych danych dla Virtualize<TItem> składnika.
StateHasChanged
element jest wywoływany w celu rerender składnika.
Symbol zastępczy
Żądanie elementów ze zdalnego źródła danych może zająć trochę czasu, dlatego istnieje możliwość renderowania symbolu zastępczego z zawartością elementu:
- Użyj znaku Placeholder (
<Placeholder>...</Placeholder>
), aby wyświetlić zawartość do momentu udostępnienia danych elementu. - Użyj Virtualize<TItem>.ItemContent polecenia , aby ustawić szablon elementu dla listy.
<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>
Pusta zawartość
Użyj parametru , EmptyContent aby podać zawartość, gdy składnik został załadowany i Items jest pusty lub ItemsProviderResult<TItem>.TotalItemCount ma wartość zero.
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();
}
Zmień metodę lambda, OnInitialized
aby wyświetlić ciągi wyświetlania składnika:
protected override void OnInitialized() =>
stringList ??= new() { "Here's a string!", "Here's another string!" };
Rozmiar elementu
Wysokość każdego elementu w pikselach można ustawić za pomocą Virtualize<TItem>.ItemSize wartości (wartość domyślna: 50). Poniższy przykład zmienia wysokość każdego elementu z wartości domyślnej 50 pikseli na 25 pikseli:
<Virtualize Context="employee" Items="employees" ItemSize="25">
...
</Virtualize>
Składnik Virtualize<TItem> mierzy rozmiar renderowania (wysokość) poszczególnych elementów po początkowym renderowaniu. Użyj ItemSize polecenia , aby zapewnić dokładny rozmiar elementu z wyprzedzeniem, aby ułatwić dokładną początkową wydajność renderowania i zapewnić poprawną pozycję przewijania strony do ponownego ładowania strony. Jeśli ustawienie domyślne ItemSize powoduje, że niektóre elementy będą renderowane poza obecnie widocznym widokiem, zostanie wyzwolony drugi rerender. Aby poprawnie zachować położenie przewijania przeglądarki na zwirtualizowanej liście, początkowy renderowanie musi być poprawne. Jeśli nie, użytkownicy mogą wyświetlać nieprawidłowe elementy.
Liczba przeskanów
Virtualize<TItem>.OverscanCount określa liczbę dodatkowych elementów renderowanych przed i po widocznym regionie. To ustawienie pomaga zmniejszyć częstotliwość renderowania podczas przewijania. Jednak wyższe wartości powodują więcej elementów renderowanych na stronie (wartość domyślna: 3). Poniższy przykład zmienia liczbę przeskanów z wartości domyślnej trzech elementów na cztery elementy:
<Virtualize Context="employee" Items="employees" OverscanCount="4">
...
</Virtualize>
Zmiany stanu
Podczas wprowadzania zmian w elementach renderowanych przez Virtualize<TItem> składnik wywołaj StateHasChanged polecenie w kolejce ponownej oceny i rerendering składnika. Aby uzyskać więcej informacji, zobacz Renderowanie składników platformy ASP.NET Core Razor.
Obsługa przewijania klawiatury
Aby umożliwić użytkownikom przewijanie zwirtualizowanej zawartości przy użyciu klawiatury, upewnij się, że zwirtualizowane elementy lub sam kontener przewijania można skupić. Jeśli nie zrobisz tego kroku, przewijanie klawiatury nie działa w przeglądarkach opartych na chromium.
Można na przykład użyć tabindex
atrybutu w kontenerze przewijania:
<div style="height:500px; overflow-y:scroll" tabindex="-1">
<Virtualize Items="allFlights">
<div class="flight-info">...</div>
</Virtualize>
</div>
Aby dowiedzieć się więcej o znaczeniu wartości , lub innych wartości, zobacz tabindex
(dokumentacja MDN).. 0
-1
tabindex
Zaawansowane style i wykrywanie przewijania
Składnik Virtualize<TItem> jest przeznaczony tylko do obsługi określonych mechanizmów układu elementów. Aby zrozumieć, które układy elementów działają poprawnie, w poniższym artykule wyjaśniono, jak Virtualize
wykrywać, które elementy powinny być widoczne dla wyświetlania we właściwym miejscu.
Jeśli kod źródłowy wygląda następująco:
<div style="height:500px; overflow-y:scroll" tabindex="-1">
<Virtualize Items="allFlights" ItemSize="100">
<div class="flight-info">Flight @context.Id</div>
</Virtualize>
</div>
W czasie wykonywania Virtualize<TItem> składnik renderuje strukturę DOM podobną do następującej:
<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>
Rzeczywista liczba renderowanych wierszy i rozmiar spacerów różnią się w zależności od stylu i Items
rozmiaru kolekcji. Należy jednak zauważyć, że istnieją elementy odstępu div
wprowadzone przed i po zawartości. Służą one dwóm celom:
- Aby podać przesunięcie przed zawartością i po niej, powodując, że aktualnie widoczne elementy będą wyświetlane w prawidłowej lokalizacji w zakresie przewijania i sam zakres przewijania reprezentujący całkowity rozmiar całej zawartości.
- Aby wykryć, kiedy użytkownik przewija się poza bieżący widoczny zakres, co oznacza, że inna zawartość musi być renderowana.
Uwaga
Aby dowiedzieć się, jak kontrolować tag elementu spacer HTML, zobacz sekcję Kontrolowanie nazwy tagu elementu spacer w dalszej części tego artykułu.
Elementy odstępu wewnętrznie używają obserwatora skrzyżowania do odbierania powiadomień, gdy staną się widoczne. Virtualize
zależy od odbierania tych zdarzeń.
Virtualize
działa w następujących warunkach:
Wszystkie renderowane elementy zawartości, w tym zawartość zastępcza, mają identyczną wysokość. Dzięki temu można obliczyć, która zawartość odpowiada danej pozycji przewijania bez uprzedniego pobierania każdego elementu danych i renderowania danych w elemencie DOM.
Zarówno odstępy, jak i wiersze zawartości są renderowane w jednym pionowym stosie z każdym elementem wypełniającym całą szerokość poziomą. W typowych przypadkach
Virtualize
użycia działa z elementamidiv
. Jeśli używasz arkuszy CSS do utworzenia bardziej zaawansowanego układu, pamiętaj o następujących wymaganiach:- Styl przewijania kontenera wymaga elementu
display
z dowolną z następujących wartości:block
(wartość domyślna dla elementudiv
).table-row-group
(wartość domyślna dla elementutbody
).flex
z ustawioną wartościąflex-direction
column
. Upewnij się, że bezpośrednie elementy podrzędne Virtualize<TItem> składnika nie kurczą się zgodnie z zasadami flex. Na przykład dodaj nazwę.mycontainer > div { flex-shrink: 0 }
.
- Styl wiersza zawartości wymaga elementu
display
z jedną z następujących wartości:block
(wartość domyślna dla elementudiv
).table-row
(wartość domyślna dla elementutr
).
- Nie należy używać arkuszy CSS do zakłócania układu elementów odstępu. Elementy odstępu mają
display
wartośćblock
, z wyjątkiem sytuacji, gdy element nadrzędny jest grupą wierszy tabeli, w tym przypadku domyślnie ma wartośćtable-row
. Nie próbuj wpływać na szerokość lub wysokość elementu odstępu, w tym przez spowodowanie, że mają obramowanie lubcontent
pseudoelementy.
- Styl przewijania kontenera wymaga elementu
Każde podejście, które uniemożliwia renderowanie elementów odstępów i zawartości jako pojedynczego stosu pionowego lub powoduje, że elementy zawartości różnią się w wysokości, uniemożliwiają prawidłowe działanie Virtualize<TItem> składnika.
Wirtualizacja na poziomie głównym
Składnik Virtualize<TItem> obsługuje używanie samego dokumentu jako katalogu głównego przewijania, jako alternatywę dla innego elementu z elementem overflow-y: scroll
. W poniższym przykładzie <html>
elementy lub <body>
są stylowane w składniku z elementem overflow-y: scroll
:
<HeadContent>
<style>
html, body { overflow-y: scroll }
</style>
</HeadContent>
Składnik Virtualize<TItem> obsługuje używanie samego dokumentu jako katalogu głównego przewijania, jako alternatywę dla innego elementu z elementem overflow-y: scroll
. W przypadku używania dokumentu jako katalogu głównego przewijania należy unikać stylów <html>
lub elementów, overflow-y: scroll
ponieważ powoduje, że obserwator skrzyżowania traktuje pełną wysokość strony jako widoczny region, a nie tylko <body>
okno viewport.
Ten problem można odtworzyć, tworząc dużą listę zwirtualizowaną (na przykład 100 000 elementów) i próbując użyć dokumentu jako katalogu głównego html { overflow-y: scroll }
przewijania w stylach CSS strony. Chociaż czasami może działać poprawnie, przeglądarka próbuje renderować wszystkie 100 000 elementów co najmniej raz na początku renderowania, co może spowodować zablokowanie karty przeglądarki.
Aby obejść ten problem przed wydaniem programu .NET 7, należy unikać tworzenia stylów <html>
/<body>
elementów za pomocą overflow-y: scroll
lub przyjąć alternatywne podejście. W poniższym przykładzie wysokość <html>
elementu jest ustawiona na nieco ponad 100% wysokości widoku:
<HeadContent>
<style>
html { min-height: calc(100vh + 0.3px) }
</style>
</HeadContent>
Składnik Virtualize<TItem> obsługuje używanie samego dokumentu jako katalogu głównego przewijania, jako alternatywę dla innego elementu z elementem overflow-y: scroll
. W przypadku używania dokumentu jako katalogu głównego przewijania należy unikać stosowania <html>
stylów lub <body>
elementów, overflow-y: scroll
ponieważ powoduje, że pełną wysokość strony można przewijać jako widoczny region, a nie tylko w oknie widoku.
Ten problem można odtworzyć, tworząc dużą listę zwirtualizowaną (na przykład 100 000 elementów) i próbując użyć dokumentu jako katalogu głównego html { overflow-y: scroll }
przewijania w stylach CSS strony. Chociaż czasami może działać poprawnie, przeglądarka próbuje renderować wszystkie 100 000 elementów co najmniej raz na początku renderowania, co może spowodować zablokowanie karty przeglądarki.
Aby obejść ten problem przed wydaniem programu .NET 7, należy unikać tworzenia stylów <html>
/<body>
elementów za pomocą overflow-y: scroll
lub przyjąć alternatywne podejście. W poniższym przykładzie wysokość <html>
elementu jest ustawiona na nieco ponad 100% wysokości widoku:
<style>
html { min-height: calc(100vh + 0.3px) }
</style>
Kontrolowanie nazwy tagu elementu spacer
Virtualize<TItem> Jeśli składnik zostanie umieszczony wewnątrz elementu, który wymaga określonej nazwy tagu podrzędnego, SpacerElement umożliwia uzyskanie lub ustawienie nazwy tagu spacer wirtualizacji. Domyślna wartość to div
. W poniższym przykładzie Virtualize<TItem> składnik renderuje się wewnątrz elementu treści tabeli (tbody
), więc odpowiedni element podrzędny dla wiersza tabeli (tr
) jest ustawiony jako odstęp.
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();
}
W poprzednim przykładzie główny dokument jest używany jako kontener przewijania, więc html
elementy i body
są stylizowany na overflow-y: scroll
. Aby uzyskać więcej informacji, zobacz następujące zasoby: