Skip to content

Commit 7a60f54

Browse files
committed
fix(virtual-repeat): handle getMore when there's no scroll and all items are in range
1 parent 4f7998d commit 7a60f54

File tree

3 files changed

+35
-13
lines changed

3 files changed

+35
-13
lines changed

src/interfaces.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -367,11 +367,15 @@ export const VirtualizationEvents = Object.assign(Object.create(null), {
367367
};
368368

369369
export const enum ScrollingState {
370-
none = 0,
371-
isScrollingDown = 0b0_00001,
372-
isScrollingUp = 0b0_00010,
373-
isNearTop = 0b0_00100,
374-
isNearBottom = 0b0_01000
370+
none = 0,
371+
isScrollingDown = 0b0_00001,
372+
isScrollingUp = 0b0_00010,
373+
isNearTop = 0b0_00100,
374+
isNearBottom = 0b0_01000,
375+
/**@internal */
376+
isScrollingDownAndNearBottom = isScrollingDown | isNearBottom,
377+
/**@internal */
378+
isScrollingUpAndNearTop = isScrollingUp | isNearTop
375379
}
376380

377381
// export const enum IVirtualRepeatState {

src/utilities-dom.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Math$round, $isNaN } from './utilities';
22
import { IView } from './interfaces';
3-
import { htmlElement } from './constants';
3+
import { htmlElement, doc } from './constants';
44

55
/**
66
* Walk up the DOM tree and determine what element will be scroller for an element
@@ -15,7 +15,7 @@ export const getScrollerElement = (element: Node): HTMLElement => {
1515
}
1616
current = current.parentNode as HTMLElement;
1717
}
18-
return htmlElement;
18+
return doc.scrollingElement as HTMLElement || htmlElement;
1919
};
2020

2121
/**

src/virtual-repeat.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ export class VirtualRepeat extends AbstractRepeater implements IVirtualRepeater
600600
// todo: use _firstViewIndex()
601601
const old_range_start_index = this.$first;
602602
const old_range_end_index = this.lastViewIndex();
603-
const [new_range_start_index, new_range_end_index] = strategy.getViewRange(this, currentScrollerInfo);
603+
const { 0: new_range_start_index, 1: new_range_end_index } = strategy.getViewRange(this, currentScrollerInfo);
604604

605605
let scrolling_state: ScrollingState =
606606
new_range_start_index > old_range_start_index
@@ -670,7 +670,10 @@ export class VirtualRepeat extends AbstractRepeater implements IVirtualRepeater
670670

671671
// intersection type 1: scrolling down but haven't reached bot
672672
// needs to move bottom views from old range (range-2) to new range (range-1)
673-
if (new_range_start_index > old_range_start_index && old_range_end_index >= new_range_start_index && new_range_end_index >= old_range_end_index) {
673+
if (new_range_start_index > old_range_start_index
674+
&& old_range_end_index >= new_range_start_index
675+
&& new_range_end_index >= old_range_end_index
676+
) {
674677
const views_to_move_count = new_range_start_index - old_range_start_index;
675678
this._moveViews(views_to_move_count, 1);
676679
didMovedViews = 1;
@@ -681,7 +684,10 @@ export class VirtualRepeat extends AbstractRepeater implements IVirtualRepeater
681684
}
682685
// intersection type 2: scrolling up but haven't reached top
683686
// this scenario requires move views from start of old range to end of new range
684-
else if (old_range_start_index > new_range_start_index && old_range_start_index <= new_range_end_index && old_range_end_index >= new_range_end_index) {
687+
else if (old_range_start_index > new_range_start_index
688+
&& old_range_start_index <= new_range_end_index
689+
&& old_range_end_index >= new_range_end_index
690+
) {
685691
const views_to_move_count = old_range_end_index - new_range_end_index;
686692
this._moveViews(views_to_move_count, -1);
687693
didMovedViews = 1;
@@ -725,10 +731,22 @@ export class VirtualRepeat extends AbstractRepeater implements IVirtualRepeater
725731
// the following block cannot be nested inside didMoveViews condition
726732
// since there could be jumpy scrolling behavior causing infinite scrollnext
727733
const all_items_in_range = this.items.length <= this.minViewsRequired * 2;
728-
const state_to_check = all_items_in_range ? ScrollingState.isNearBottom : (ScrollingState.isNearBottom | ScrollingState.isScrollingDown);
729734
if (
730-
(scrolling_state & state_to_check) === state_to_check
731-
|| (scrolling_state & (ScrollingState.isScrollingUp | ScrollingState.isNearTop)) === (ScrollingState.isScrollingUp | ScrollingState.isNearTop)
735+
(scrolling_state & ScrollingState.isScrollingDownAndNearBottom) === ScrollingState.isScrollingDownAndNearBottom
736+
|| (scrolling_state & ScrollingState.isScrollingUpAndNearTop) === ScrollingState.isScrollingUpAndNearTop
737+
|| all_items_in_range
738+
// when all items in range, and somehow scroll handle is trigger
739+
// but the scroll direction couldn't be derived from the view index (scroll too little etc...)
740+
// then do check further to see if it's appropriate to load more
741+
// via either:
742+
// all items in range + not scrolling up + is near bottom
743+
&& ((scrolling_state & ScrollingState.isScrollingUp) === 0
744+
&& (scrolling_state & ScrollingState.isNearBottom) === ScrollingState.isNearBottom
745+
// or
746+
// all items in range + not scrolling down + is near top
747+
|| (scrolling_state & ScrollingState.isScrollingDown) === 0
748+
&& (scrolling_state & ScrollingState.isNearTop) === ScrollingState.isNearTop
749+
)
732750
) {
733751
this.getMore(
734752
new_range_start_index,

0 commit comments

Comments
 (0)