Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Jegyzet
Ez nem a cikk legújabb verziója. Az aktuális kiadásról a cikk .NET 10-es verziójában olvashat.
Figyelmeztetés
A ASP.NET Core ezen verziója már nem támogatott. További információ: .NET és .NET Core támogatási szabályzat. Az aktuális kiadásához tekintse meg a jelen cikk .NET 9-es verzióját.
Ez a cikk azt ismerteti, hogyan használható az összetevők virtualizálása ASP.NET Core Blazor-alkalmazásokban.
Virtualizálás
Az összetevők renderelésének érzékelt teljesítményének javítása a Blazor keretrendszer beépített virtualizálási támogatásával az Virtualize<TItem> összetevővel. A virtualizálás olyan technika, amellyel a felhasználói felületi megjelenítés csak a jelenleg látható részekre korlátozható. A virtualizálás például akkor hasznos, ha az alkalmazásnak hosszú elemeket kell megjelenítenie, és csak az elemek egy részhalmazának kell megjelennie egy adott időpontban.
Használja a Virtualize<TItem> összetevőt a következő esetekben:
- Adatelemek egy halmazának renderelése egy ciklusban.
- A legtöbb elem görgetés miatt nem látható.
- A renderelt elemek mérete megegyezik.
Amikor a felhasználó a Virtualize<TItem> összetevő elemeinek listájában tetszőleges pontra görget, az összetevő kiszámítja a megjelenítendő látható elemeket. A nem látott elemek nem jelennek meg.
Virtualizálás nélkül egy tipikus lista C# foreach ciklust használhat a lista egyes elemeinek megjelenítéséhez. Az alábbi példában:
-
allFlightsrepülőjáratok gyűjteménye. - A
FlightSummaryösszetevő az egyes járatokkal kapcsolatos részleteket jeleníti meg. - A
@keyirányelv attribútuma megőrzi az egyesFlightSummaryösszetevők és a repülőjáratFlightIdáltal renderelt repülés közötti kapcsolatot.
<div style="height:500px;overflow-y:scroll">
@foreach (var flight in allFlights)
{
<FlightSummary @key="flight.FlightId" Details="@flight.Summary" />
}
</div>
Ha a gyűjtemény több ezer járatot tartalmaz, a járatok renderelése hosszú időt vesz igénybe, és a felhasználók észrevehető felhasználói felületi késést tapasztalnak. A legtöbb járat a <div> elem magasságán kívül esik, így a legtöbbjük nem látható.
Ahelyett, hogy egyszerre renderelné a teljes járatlistát, cserélje le az előző példában szereplő foreach hurkot a Virtualize<TItem> összetevőre:
Adja meg a
allFlightsszámára, hogy a Virtualize<TItem>.Items rögzített elemforrás. A Virtualize<TItem> összetevő csak a jelenleg látható járatokat jeleníti meg.Ha egy nem általános gyűjtemény látja el az elemeket, például egy DataRowgyűjteményt, kövesse az Elemszolgáltató delegálási szakasz útmutatását az elemek megadásához.
Adjon meg egy környezetet minden egyes járathoz a
Contextparaméterrel. Az alábbi példában aflighthasználjuk kontextusként, amely hozzáférést biztosít az egyes járatok tagjaihoz.
<div style="height:500px;overflow-y:scroll">
<Virtualize Items="allFlights" Context="flight">
<FlightSummary @key="flight.FlightId" Details="@flight.Summary" />
</Virtualize>
</div>
Ha nincs megadva kontextus a Context paraméterrel, használja az elem tartalomsablonjában szereplő context értékét az egyes járatok tagjai eléréséhez.
<div style="height:500px;overflow-y:scroll">
<Virtualize Items="allFlights">
<FlightSummary @key="context.FlightId" Details="@context.Summary" />
</Virtualize>
</div>
A Virtualize<TItem> összetevő:
- Kiszámítja a megjelenítendő elemek számát a tároló magassága és a renderelt elemek mérete alapján.
- A felhasználó görgetése közben újraszámítja és újrarendezi az elemeket.
- Csak a jelenleg látható régiónak megfelelő rekordszeletet olvassa be egy külső API-ból, beleértve az előolvasást is, ha az
ItemsProviderhelyett azItemsvan használva (lásd az Elemszolgáltató delegált szakaszát).
A Virtualize<TItem> összetevő elemtartalma a következőket tartalmazhatja:
- Egyszerű HTML- és Razor-kód, ahogy az előző példa is mutatja.
- Egy vagy több Razor összetevő.
- HTML/Razor és Razor összetevők keveréke.
Elemek szolgáltatójának delegáltja
Ha nem szeretné betölteni az összes elemet a memóriába, vagy a gyűjtemény nem általános ICollection<T>, megadhatja az elemszolgáltató delegálási módszerét az összetevő Virtualize<TItem>.ItemsProvider paraméteréhez, amely aszinkron módon kéri le a kért elemeket igény szerint. Az alábbi példában a LoadEmployees metódus biztosítja az elemeket a Virtualize<TItem> összetevőnek:
<Virtualize Context="employee" ItemsProvider="LoadEmployees">
<p>
@employee.FirstName @employee.LastName has the
job title of @employee.JobTitle.
</p>
</Virtualize>
Az elemszolgáltató kap egy ItemsProviderRequest, amely meghatározza az adott kezdőindextől kezdődően szükséges számú elemet. Az elemszolgáltató ezután lekéri a kért elemeket egy adatbázisból vagy más szolgáltatásból, és ItemsProviderResult<TItem> ként adja vissza őket, valamint a teljes elemek számát. Az elemek szolgáltatója dönthet úgy, hogy lekéri az elemeket az egyes kérésekkel, vagy gyorsítótárba helyezi őket, hogy azok könnyen elérhetők legyenek.
Egy Virtualize<TItem> összetevő csak egy elemforrást képes elfogadni a paramétereiből, ezért ne próbáljon ki egyszerre egy elemszolgáltatót használni és egy gyűjteményt hozzárendelni Items. Ha mindkettő ki van rendelve, a rendszer InvalidOperationException dob, amikor az összetevő paraméterei futásidőben vannak beállítva.
Az alábbi példa betölti az alkalmazottakat a EmployeeService-ból (nem látható). A totalEmployees mező általában úgy van hozzárendelve, hogy egy metódust hív meg ugyanazon a szolgáltatáson (például EmployeesService.GetEmployeesCountAsync) máshol, például az összetevők inicializálása során.
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);
}
Az alábbi példában a DataRow gyűjteménye nem általános gyűjtemény, ezért a virtualizáláshoz egy elemszolgáltatói meghatalmazottat használunk:
<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 utasítja a komponenst, hogy kérelmezze újra az adatokat a ItemsProvider-től. Ez akkor hasznos, ha külső adatok változnak. A RefreshDataAsynchasználatakor általában nincs szükség Items hívására.
RefreshDataAsync anélkül frissíti egy Virtualize<TItem>-összetevő adatait, hogy újrarajzolást okozna. Ha a RefreshDataAsync-t egy Blazor eseménykezelőből vagy egy összetevő életciklus-metódusából hívják meg, a renderelés elindítása nem szükséges, mert a renderelés automatikusan elindul az eseménykezelő vagy az összetevő életciklus-metódusa végén. Ha RefreshDataAsync háttérfeladattól vagy eseménytől függetlenül aktiválódik, például a következő ForecastUpdated delegáltban, hívja meg a StateHasChanged, hogy frissítse a felhasználói felületet a háttérfeladat vagy esemény végén:
<Virtualize ... @ref="virtualizeComponent">
...
</Virtualize>
...
private Virtualize<FetchData>? virtualizeComponent;
protected override void OnInitialized()
{
WeatherForecastSource.ForecastUpdated += async () =>
{
await InvokeAsync(async () =>
{
await virtualizeComponent?.RefreshDataAsync();
StateHasChanged();
});
});
}
Az előző példában:
- RefreshDataAsync elsőként az Virtualize<TItem> összetevő új adatainak lekéréséhez hívjuk meg.
-
StateHasChangedaz összetevő újrarendelésére van meghívva.
Helykitöltő
Mivel egy távoli adatforrásból való elemek kérése eltarthat egy ideig, lehetősége van egy elemtartalommal rendelkező helyőrző megjelenítésére:
- A tartalom megjelenítéséhez használjon Placeholder (
<Placeholder>...</Placeholder>), amíg az elem adatai nem lesznek elérhetők. - A lista elemsablonjának beállításához használja a Virtualize<TItem>.ItemContent.
<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>
Üres tartalom
A EmptyContent paraméter használatával adja meg a tartalmat, ha az összetevő betöltődött, és Items üres, vagy ItemsProviderResult<TItem>.TotalItemCount nulla.
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 ??= [];
}
Módosítsa a OnInitialized metódus lambdát az összetevő megjelenítési sztringjeinek megtekintéséhez:
protected override void OnInitialized() =>
stringList ??= [ "Here's a string!", "Here's another string!" ];
Elem mérete
A képpontban lévő elemek magassága Virtualize<TItem>.ItemSize (alapértelmezett: 50) beállítással állítható be. Az alábbi példa az egyes elemek magasságát az alapértelmezett 50 képpontról 25 képpontra módosítja:
<Virtualize Context="employee" Items="employees" ItemSize="25">
...
</Virtualize>
A Virtualize<TItem> összetevő az egyes elemek renderelési méretét (magasságát) méri, a kezdeti renderelés után. A ItemSize segítségével előre pontos elemméretet adhat meg a pontos kezdeti renderelési teljesítményhez, és biztosíthatja a lap újrabetöltéséhez szükséges megfelelő görgetési pozíciót. Ha az alapértelmezett ItemSize miatt egyes elemek az aktuálisan látható nézeten kívül jelennek meg, a rendszer elindít egy második rerendert. A böngésző görgetési pozíciójának virtualizált listában való megfelelő fenntartásához a kezdeti renderelésnek helyesnek kell lennie. Ha nem, előfordulhat, hogy a felhasználók nem a megfelelő elemeket tekintik meg.
Túlvezérlés száma
Virtualize<TItem>.OverscanCount meghatározza, hogy hány további elem jelenik meg a látható régió előtt és után. Ez a beállítás segít csökkenteni a renderelés gyakoriságát a görgetés során. A magasabb értékek azonban több elemet eredményeznek a lapon (alapértelmezett: 3). Az alábbi példa a túlmérés számát a három elem alapértelmezett értékéről négy elemre módosítja.
<Virtualize Context="employee" Items="employees" OverscanCount="4">
...
</Virtualize>
Állapotváltozások
Az Virtualize<TItem> összetevő által renderelt elemek módosításakor hívja meg a StateHasChanged az összetevő újraértékelésének és újrarendezésének lekéréséhez. További információért lásd: ASP.NET Core Razor összetevő renderelése.
A billentyűzet görgetési támogatása
Annak érdekében, hogy a felhasználók a billentyűzetükkel görgethessék a virtualizált tartalmakat, győződjön meg arról, hogy a virtualizált elemek vagy maga a görgetőtároló fókuszba helyezhető. Ha nem tudja elvégezni ezt a lépést, a billentyűzet görgetése nem működik a Chromium-alapú böngészőkben.
Használhat például egy tabindex attribútumot a görgetőtárolón:
<div style="height:500px; overflow-y:scroll" tabindex="-1">
<Virtualize Items="allFlights">
<div class="flight-info">...</div>
</Virtualize>
</div>
Ha többet szeretne megtudni az érték tabindexjelentéséről -1 , 0vagy más értékekről, olvassa el a következőttabindex: .
Speciális stílusok és görgetésészlelés
A Virtualize<TItem> összetevő csak bizonyos elemelrendezési mechanizmusok támogatására lett kialakítva. Annak megértéséhez, hogy mely elemelrendezések működnek megfelelően, az alábbiakból megtudhatja, hogyan észleli Virtualize, hogy mely elemek jelenjenek meg a megfelelő helyen.
Ha a forráskód a következőhöz hasonlóan néz ki:
<div style="height:500px; overflow-y:scroll" tabindex="-1">
<Virtualize Items="allFlights" ItemSize="100">
<div class="flight-info">Flight @context.Id</div>
</Virtualize>
</div>
Futásidőben a Virtualize<TItem> összetevő az alábbihoz hasonló DOM-struktúrát jelenít meg:
<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>
A megjelenített sorok tényleges száma és a távtartók mérete a stílustól és a Items gyűjtemény méretétől függően változik. Figyelje meg azonban, hogy a tartalom előtt és után elválasztó div elemek vannak beszúrva. Ezek két célt szolgálnak:
- Ha eltolást szeretne biztosítani a tartalom előtt és után, az aktuálisan látható elemek a görgetési tartomány megfelelő helyén jelennek meg, és maga a görgetési tartomány az összes tartalom teljes méretét jelzi.
- Annak észleléséhez, hogy a felhasználó mikor görget az aktuális látható tartományon túl, vagyis különböző tartalmakat kell megjelenítenie.
Jegyzet
A távtartó HTML-elemcímkéjének szabályozásáról a jelen cikk későbbi, Távtartó elemcímke nevének szabályozása szakaszában olvashat.
A távtartó elemek belsőleg egy metszetmegfigyelő használatával kapnak értesítést, amikor láthatóvá válnak.
Virtualize az események fogadásától függ.
Virtualize a következő feltételek mellett működik:
Minden renderelt tartalomelem, beleértve helyőrző tartalmat, azonos magasságú. Ez lehetővé teszi, hogy kiszámítsa, melyik tartalom felel meg egy adott görgetési pozíciónak anélkül, hogy minden adatelemet beolvas, és az adatokat egy DOM-elembe renderelné.
A távtartók és a tartalomsorok is egyetlen függőleges sorban jelennek meg, és minden elem kitölti a teljes vízszintes szélességet. Általában
Virtualizedivelemekkel működik. Ha CSS-t használ egy fejlettebb elrendezés létrehozásához, vegye figyelembe az alábbi követelményeket:- A görgetőtartály stílusához szükséges egy
display, amely az alábbi értékek bármelyikét tartalmazza:-
block(az alapértelmezettdiv). -
table-row-group(az alapértelmezetttbody). -
flexflex-directioncolumnértékre van állítva. Győződjön meg arról, hogy a Virtualize<TItem> komponens közvetlen gyermekei nem zsugorodnak a flex szabályok alapján. Például add hozzá a.mycontainer > div { flex-shrink: 0 }-át.
-
- A tartalomsor-stílushoz az alábbi értékek valamelyikével rendelkező
displayszükséges:-
block(az alapértelmezettdiv). -
table-row(az alapértelmezetttr).
-
- Ne használja a CSS-t a távtartó elemeinek elrendezésébe való beavatkozásra. A szóköz elemei
displayblockértékkel rendelkeznek, kivéve, ha a szülő egy táblasorcsoport; ilyen esetbentable-rowlesz az alapértelmezett értékük. Ne próbálja befolyásolni a távtartó elem szélességét vagy magasságát, többek között azzal, hogy szegélyt vagycontentpszeudoelemeket ad hozzá.
- A görgetőtartály stílusához szükséges egy
Minden olyan megközelítés, amely megakadályozza, hogy a távtartók és a tartalomelemek egyetlen függőleges veremként jelenjenek meg, vagy a tartalomelemek magassága eltérő legyen, megakadályozza a Virtualize<TItem> összetevő megfelelő működését.
Gyökérszintű virtualizálás
A Virtualize<TItem> összetevő támogatja a dokumentum görgetőgyökérként való használatát, alternatívaként pedig más elemet is használhat overflow-y: scroll. Az alábbi példában a <html> vagy <body> elemek egy overflow-y: scroll-t tartalmazó összetevőben stílussal rendelkeznek.
<HeadContent>
<style>
html, body { overflow-y: scroll }
</style>
</HeadContent>
A Virtualize<TItem> összetevő támogatja a dokumentum görgetőgyökérként való használatát, alternatívaként pedig más elemet is használhat overflow-y: scroll. Amikor a dokumentumot görgetőgyökérként használja, kerülje a <html> vagy <body> elemek stílusának overflow-y: scroll való alkalmazását, mert ez az metszetfigyelő számára az oldal teljes görgethető magasságát látható régióként kezeli, nem csak az ablaknézetet.
Ezt a problémát egy nagy virtualizált lista (például 100 000 elem) létrehozásával reprodukálhatja, és megpróbálhatja a dokumentumot görgetőgyökérként használni a lap CSS-stílusaiban html { overflow-y: scroll }. Bár időnként helyesen működik, a böngésző a renderelés kezdetén legalább egyszer megkísérli megjeleníteni az összes 100 000 elemet, ami a böngésző lapzárolását okozhatja.
Ha a .NET 7 kiadása előtt szeretné megkerülni ezt a problémát, kerülje <html>/<body> elemek overflow-y: scroll való stílusát, vagy alkalmazzon alternatív megközelítést. Az alábbi példában a <html> elem magassága úgy van beállítva, hogy alig több mint 100% legyen a nézetport magasságából.
<HeadContent>
<style>
html { min-height: calc(100vh + 0.3px) }
</style>
</HeadContent>
A Virtualize<TItem> összetevő támogatja a dokumentum görgetőgyökérként való használatát, alternatívaként pedig más elemet is használhat overflow-y: scroll. Ha a dokumentumot használja görgető gyökérként, kerülje el a <html> vagy <body> elemek overflow-y: scroll-val való stílusát, mert ez azt eredményezi, hogy az oldal teljes görgethető magassága a látható régióként lesz kezelve, nem csak az ablak nézetportja.
Ezt a problémát egy nagy virtualizált lista (például 100 000 elem) létrehozásával reprodukálhatja, és megpróbálhatja a dokumentumot görgetőgyökérként használni a lap CSS-stílusaiban html { overflow-y: scroll }. Bár időnként helyesen működik, a böngésző a renderelés kezdetén legalább egyszer megkísérli megjeleníteni az összes 100 000 elemet, ami a böngésző lapzárolását okozhatja.
Ha a .NET 7 kiadása előtt szeretné megkerülni ezt a problémát, kerülje <html>/<body> elemek overflow-y: scroll való stílusát, vagy alkalmazzon alternatív megközelítést. Az alábbi példában a <html> elem magassága úgy van beállítva, hogy alig több mint 100% legyen a nézetport magasságából.
<style>
html { min-height: calc(100vh + 0.3px) }
</style>
A távtartó elem címkéjének nevének szabályozása
Ha a Virtualize<TItem> komponens egy meghatározott gyermek címke nevet igénylő elembe kerül, SpacerElement lehetővé teszi a virtualizálási távtartó címke nevének lekérését vagy beállítását. Az alapértelmezett érték a div. Az alábbi példában a Virtualize<TItem> összetevő egy táblázattörzselemen (tbody) belül jelenik meg, így a táblázatsor (tr) megfelelő gyermekeleme szóközként van beállítva.
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();
}
Az előző példában a dokumentumgyökér szolgál görgetőtárolóként, így a html és body elemek overflow-y: scrollszerint vannak megformázva. További információ: