Skip to content

Commit 8418ef6

Browse files
Various virtualization improvements. Fixes #25535 (#25260)
* Use ItemSize if it's close to the calculated item size. * Update WeatherForecastService.cs * Improved item size calculation. * Always use calculated item size * Disable overflow anchoring on scroll containers (except the document itself) * Update JS files following rebase * Apply overflow anchor fix to document element too * Add OverscanCount parameter Co-authored-by: Steve Sanderson <[email protected]>
1 parent 12c0165 commit 8418ef6

File tree

4 files changed

+24
-7
lines changed

4 files changed

+24
-7
lines changed

src/Components/Web.JS/dist/Release/blazor.server.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Components/Web.JS/dist/Release/blazor.webassembly.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Components/Web.JS/src/Virtualize.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export const Virtualize = {
55

66
const observersByDotNetId = {};
77

8-
function findClosestScrollContainer(element: Element | null): Element | null {
8+
function findClosestScrollContainer(element: HTMLElement | null): HTMLElement | null {
99
if (!element) {
1010
return null;
1111
}
@@ -20,8 +20,14 @@ function findClosestScrollContainer(element: Element | null): Element | null {
2020
}
2121

2222
function init(dotNetHelper: any, spacerBefore: HTMLElement, spacerAfter: HTMLElement, rootMargin = 50): void {
23+
// Overflow anchoring can cause an ongoing scroll loop, because when we resize the spacers, the browser
24+
// would update the scroll position to compensate. Then the spacer would remain visible and we'd keep on
25+
// trying to resize it.
26+
const scrollContainer = findClosestScrollContainer(spacerBefore);
27+
(scrollContainer || document.documentElement).style.overflowAnchor = 'none';
28+
2329
const intersectionObserver = new IntersectionObserver(intersectionCallback, {
24-
root: findClosestScrollContainer(spacerBefore),
30+
root: scrollContainer,
2531
rootMargin: `${rootMargin}px`,
2632
});
2733

@@ -57,7 +63,9 @@ function init(dotNetHelper: any, spacerBefore: HTMLElement, spacerAfter: HTMLEle
5763
return;
5864
}
5965

60-
const spacerSeparation = spacerAfter.offsetTop - (spacerBefore.offsetTop + spacerBefore.offsetHeight);
66+
const spacerBeforeRect = spacerBefore.getBoundingClientRect();
67+
const spacerAfterRect = spacerAfter.getBoundingClientRect();
68+
const spacerSeparation = spacerAfterRect.top - spacerBeforeRect.bottom;
6169
const containerSize = entry.rootBounds?.height;
6270

6371
if (entry.target === spacerBefore) {

src/Components/Web/src/Virtualization/Virtualize.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,15 @@ public sealed class Virtualize<TItem> : ComponentBase, IVirtualizeJsCallbacks, I
8888
[Parameter]
8989
public ICollection<TItem>? Items { get; set; }
9090

91+
/// <summary>
92+
/// Gets or sets a value that determines how many additional items will be rendered
93+
/// before and after the visible region. This help to reduce the frequency of rendering
94+
/// during scrolling. However, higher values mean that more elements will be present
95+
/// in the page.
96+
/// </summary>
97+
[Parameter]
98+
public int OverscanCount { get; set; } = 3;
99+
91100
/// <inheritdoc />
92101
protected override void OnParametersSet()
93102
{
@@ -251,8 +260,8 @@ private void CalcualteItemDistribution(
251260
_itemSize = ItemSize;
252261
}
253262

254-
itemsInSpacer = Math.Max(0, (int)Math.Floor(spacerSize / _itemSize) - 1);
255-
visibleItemCapacity = (int)Math.Ceiling(containerSize / _itemSize) + 2;
263+
itemsInSpacer = Math.Max(0, (int)Math.Floor(spacerSize / _itemSize) - OverscanCount);
264+
visibleItemCapacity = (int)Math.Ceiling(containerSize / _itemSize) + 2 * OverscanCount;
256265
}
257266

258267
private void UpdateItemDistribution(int itemsBefore, int visibleItemCapacity)

0 commit comments

Comments
 (0)