I tried to write a virtual scroll in pure JS, but when I scroll down, the scrolling does not stop. I can't figure out what's causing the infinite scrolling.
To emulate scrolling, I use two containers, top and bottom. During scrolling, I proportionally change their height and at the same time rerender the internal content.
class VirtualScroll {
constructor(selector, visibleRows = 0, amount, rowHeight) {
this.scrollContainer = document.querySelector(selector);
if (!this.scrollContainer) {
return false;
}
this.rowHeight = rowHeight;
this.visibleRows = visibleRows;
this.start = 0;
this.data = this.createTableData(amount);
// Верхнее пространство для скролла
this.topSpace = document.createElement("div");
this.topSpace.classList.add('hidden-top');
this.topSpace.style = `height: ${this.getTopHeight()}px;`;
this.scrollContainer.appendChild(this.topSpace);
// Создание пространство видимых блоков
this.container = document.createElement("div");
this.container.classList.add('scroll-container');
this.fillContainer();
this.scrollContainer.appendChild(this.container);
// Верхнее пространство для скролла
this.bottomSpace = document.createElement("div");
this.bottomSpace.classList.add('hidden-bottom');
this.bottomSpace.style = `height: ${this.getBottomHeight()}px`
this.scrollContainer.appendChild(this.bottomSpace);
this.scrollContainer.addEventListener('scroll', (e) => {
const oldStart = this.start + 0;
this.start = Math.min(
this.data.length - this.visibleRows - 1,
Math.floor(e.target.scrollTop / this.rowHeight)
)
if (oldStart === this.start) {
return false;
}
this.bottomSpace.style = `height: ${this.getBottomHeight()}px`;
this.topSpace.style = `height: ${this.getTopHeight()}px;`;
this.fillContainer();
});
}
getTopHeight() {
return this.rowHeight * this.start;
}
getBottomHeight() {
return this.rowHeight * (this.data.length - (this.start + this.visibleRows + 1));
}
createTableData(h) {
return new Array(h).fill(0).map((_, row) => {
return row;
});
}
// Заполнение контейнера видимыми блоками
fillContainer() {
this.container.innerHTML = "";
this.data.slice(this.start, this.start + this.visibleRows + 1).map((row, rowIndex) => {
const item = document.createElement("div");
item.classList.add('scroll-item');
item.innerText = row;
item.id = this.start + ' ' + rowIndex + row;
this.container.appendChild(item);
})
}
}
new VirtualScroll(".container", 4, 100, 30);
* {
box-sizing: border-box;
}
.container {
height: 120px;
overflow-y: auto;
}
.scroll-container {
width: 100%;
}
.scroll-item {
height: 30px;
border: 1px solid black;
padding: 10px;
color: black;
}
<div class="container"> </div>
I hope more attentive and skillful developers will tell me what’s wrong.