Каталог Wildberries в категории «Платья» — 10 000 карточек. Если отрендерить все, на телефоне это 10 000 DOM-узлов и секунды на прокрутку. Виртуальный список рендерит только видимые строки и несколько про запас.
Напишите getVisibleRange({ scrollTop, viewportHeight, rowHeight, total, overscan }) → { start, end, offset }. Строки с индексами start ≤ i < end рендерим, offset = start * rowHeight — сдвиг первой строки. Видимые строки — те, что хоть частично попадают в окно; добавьте overscan строк сверху и снизу.
scrollTop бывает отрицательным (пружина на iOS) и больше максимума (после удаления товаров) — ограничьте его диапазоном [0, max(0, total * rowHeight - viewportHeight)]. Индексы не выходят за [0, total].
В работе: Длинные ленты, таблицы с тысячами строк, чаты.
Пример 1: вверху ленты
{"total": 10000, "overscan": 3, "rowHeight": 120, "scrollTop": 0, "viewportHeight": 800}{"end": 10, "start": 0, "offset": 0}Пример 2: середина
{"total": 10000, "overscan": 3, "rowHeight": 120, "scrollTop": 12000, "viewportHeight": 800}{"end": 110, "start": 97, "offset": 11640}getVisibleRange — тест вызывает её сам. Таймеры и Date в тестах ненастоящие: время идёт по команде теста, поэтому setTimeout на 5 секунд проверяется мгновенно. Тестов 8: 2 открыты выше, остальные приходят после старта подхода. Лимит — 2 с на тест.
function getVisibleRange({ scrollTop, viewportHeight, rowHeight, total, overscan }) // → { start, end, offset }
Источник: на задачах Wildberries: лента каталога. Условие пересказано своими словами.
Ожидаемый ответ не нужен: покажем, что вернула функция.
Здесь появится результат отправки.