feat(VirtualList): add onJump callback for scroll-beyond-loaded detection
This commit is contained in:
@@ -62,6 +62,10 @@ interface Props extends
|
|||||||
* Near bottom callback
|
* Near bottom callback
|
||||||
*/
|
*/
|
||||||
onNearBottom?: (lastVisibleIndex: number) => void;
|
onNearBottom?: (lastVisibleIndex: number) => void;
|
||||||
|
/**
|
||||||
|
* Fires when scroll position exceeds loaded content — user jumped beyond data
|
||||||
|
*/
|
||||||
|
onJump?: (targetIndex: number) => void;
|
||||||
/**
|
/**
|
||||||
* Item render snippet
|
* Item render snippet
|
||||||
*/
|
*/
|
||||||
@@ -95,6 +99,7 @@ let {
|
|||||||
class: className,
|
class: className,
|
||||||
onVisibleItemsChange,
|
onVisibleItemsChange,
|
||||||
onNearBottom,
|
onNearBottom,
|
||||||
|
onJump,
|
||||||
children,
|
children,
|
||||||
useWindowScroll = false,
|
useWindowScroll = false,
|
||||||
isLoading = false,
|
isLoading = false,
|
||||||
@@ -170,6 +175,10 @@ const throttledNearBottom = throttle((lastVisibleIndex: number) => {
|
|||||||
onNearBottom?.(lastVisibleIndex);
|
onNearBottom?.(lastVisibleIndex);
|
||||||
}, 200); // 200ms throttle
|
}, 200); // 200ms throttle
|
||||||
|
|
||||||
|
const throttledOnJump = throttle((targetIndex: number) => {
|
||||||
|
onJump?.(targetIndex);
|
||||||
|
}, 200);
|
||||||
|
|
||||||
// Calculate top/bottom padding for spacer elements
|
// Calculate top/bottom padding for spacer elements
|
||||||
// In CSS Grid, gap creates space BETWEEN elements.
|
// In CSS Grid, gap creates space BETWEEN elements.
|
||||||
// The top spacer should place the first row at its virtual offset.
|
// The top spacer should place the first row at its virtual offset.
|
||||||
@@ -227,6 +236,26 @@ $effect(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
// Fire onJump when scroll is beyond the loaded content boundary.
|
||||||
|
// Target index estimates which item the user scrolled to.
|
||||||
|
if (!onJump || !virtualizer.containerHeight || virtualizer.scrollOffset <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isAhead = virtualizer.scrollOffset > virtualizer.totalSize;
|
||||||
|
if (!isAhead) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const estimatedItemHeight = typeof itemHeight === 'number' ? itemHeight : 80;
|
||||||
|
// Include visible rows + overscan so the bottom of the viewport is fully covered
|
||||||
|
const topItemIndex = Math.floor(virtualizer.scrollOffset / estimatedItemHeight) * columns;
|
||||||
|
const visibleRows = Math.ceil(virtualizer.containerHeight / estimatedItemHeight);
|
||||||
|
const targetIndex = topItemIndex + (visibleRows + overscan) * columns;
|
||||||
|
throttledOnJump(targetIndex);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#snippet content()}
|
{#snippet content()}
|
||||||
|
|||||||
Reference in New Issue
Block a user