Back to questions
Middle
7
Реализовать виртуальный скролл: есть длинный список сообщений (10 000 элементов), нужно рендерить только видимые элементы внутри контейнера с фиксированной высотой 300px, высота одной строки — 30px.
Companies where asked
Basis
Answer from AI
sobes.tech AI
Для реализации виртуального скролла с 10 000 элементами и фиксированной высотой контейнера 300px (высота строки 30px) можно использовать следующий подход:
- Вычислить количество видимых элементов: 300px / 30px = 10 элементов.
- Отслеживать текущий скролл контейнера и вычислять индекс первого видимого элемента:
startIndex = Math.floor(scrollTop / 30). - Рендерить только элементы с индексами от
startIndexдоstartIndex + visibleCount + buffer(buffer — небольшой запас, например 2 элемента, чтобы избежать мерцания). - Для сохранения общей высоты списка использовать пустой блок с высотой
totalHeight = 10000 * 30 = 300000px. - Сдвигать контейнер с видимыми элементами вниз на
startIndex * 30pxс помощью CSStransformилиpadding-top.
Пример на React:
function VirtualList({ items }) {
const containerHeight = 300;
const rowHeight = 30;
const totalCount = items.length;
const visibleCount = Math.ceil(containerHeight / rowHeight);
const buffer = 2;
const [scrollTop, setScrollTop] = React.useState(0);
const startIndex = Math.floor(scrollTop / rowHeight);
const endIndex = Math.min(startIndex + visibleCount + buffer, totalCount);
const visibleItems = items.slice(startIndex, endIndex);
const onScroll = (e) => {
setScrollTop(e.currentTarget.scrollTop);
};
return (
<div style={{ height: containerHeight, overflowY: 'auto' }} onScroll={onScroll}>
<div style={{ height: totalCount * rowHeight, position: 'relative' }}>
<div style={{
position: 'absolute',
top: startIndex * rowHeight,
left: 0,
right: 0
}}>
{visibleItems.map((item, index) => (
<div key={startIndex + index} style={{ height: rowHeight }}>
{item}
</div>
))}
</div>
</div>
</div>
);
}
Такой подход позволяет эффективно рендерить только видимые элементы, экономя ресурсы браузера.