Я пытаюсь реализовать бесконечную прокрутку. Я использовал этот подход. Вроде все работает нормально. Но при выполнении прокрутки, вместо реального дома появляется какой-то белый фон. Я проверил, что дом уже добавлен в сетку, хотя белый фон приходит. Я приложил свой код здесь. Пожалуйста, помогите мне исправить. Codepen
Примечание. Чтобы воспроизвести, откройте в режиме просмотра полной страницы и попробуйте прокрутить во всех направлениях. (Иногда это не происходит при вертикальной прокрутке, но она определенно воспроизводима при вертикальной прокрутке в противоположную сторону. .)
const TOP = 0;
const LEFT = 1;
const RIGHT = 2;
const BOTTOM = 3;
const PADDING_COUNT = 2; // Extra DOM Count will be rendered on each side of grid.
const PREPOPULATION_COUNT = 25; // Rendered on Scroll Direction
const SCROLL_RUNWAY = 2000;
var i = 0,
j = 0,
len = 0,
scrollleft, scrolltop, cell, node, coords;
class Grid {
constructor(source, scroller) {
this.source = source;
this.scroller = scroller;
this.scrollerHeight = this.scroller.offsetHeight;
this.scrollerWidth = this.scroller.offsetWidth;
this.boundries = [0, 0, 0, 0];
this.scrollTop = 0;
this.scrollLeft = 0;
this.scrollRunwayRight = 0;
this.scrollRunwayBottom = 0;
this.scroller.classList.add('grid');
//RUN WAY PREPARATION
this.scrollRunway = document.createElement('div');
this.scrollRunway.textContent = ' ';
this.scrollRunway.style.position = 'absolute';
this.scrollRunway.style.height = '1px';
this.scrollRunway.style.width = '1px';
this.scrollRunway.style.transition = 'transform 0.2s';
this.scroller.append(this.scrollRunway);
this.unusednodes = [];
//EVENT PREPARATION
this.scroller.addEventListener('scroll', this.onResize.bind(this));
window.addEventListener('resize', this.onResize.bind(this));
this.dom = [];
this.map = {};
this.linkedGrids = [];
this.cellWidth = this.source.getCellWidth();
this.cellHeight = this.source.getCellHeight();
this.onResize();
}
syncGrid(sl, st) {
this.linkedGrids.forEach(grid => {
//sync each grid
});
}
onResize() {
this.scrollerHeight = this.scroller.offsetHeight;
this.scrollerWidth = this.scroller.offsetWidth;
this.onScroll();
}
fillGrid(left, right, top, bottom) {
//console.log("left=",left,"right=",right,"top",top,"bottom",bottom);
len = this.dom.length;
var latest = [];
//Clear Unnecessary DOM
this.map = {};
for (i = 0; i < len; i++) {
cell = this.dom[i];
if (cell.row <= bottom && cell.row >= top && cell.col >= left && cell.col <= right) {
this.map[cell.row + '' + cell.col] = true;
latest.push(cell);
continue;
}
this.unusednodes.push(cell.node);
this.map[cell.row + '' + cell.col] = false;
}
this.dom = latest;
//Create New DOM
for (i = top; i <= bottom; i++) {
for (j = left; j <= right; j++) {
if (!this.map[i + '' + j]) {
node = this.source.render(this.getFreeNode(), i, j);
this.dom.push({
row: i,
col: j,
node: node
});
coords = this.source.getCellCoordinates(i, j);
node.style.transform = 'translate(' + coords.y + 'px,' + coords.x + 'px)'; //left,top,z
this.scroller.append(node);
}
}
}
coords = this.source.getCellCoordinates(right, bottom);
this.scrollRunwayRight = Math.max(this.scrollRunwayRight, coords.y + SCROLL_RUNWAY);
this.scrollRunwayBottom = Math.max(this.scrollRunwayBottom, coords.x + SCROLL_RUNWAY);
this.scrollRunway.style.transform = 'translate(' + this.scrollRunwayRight + 'px,' + this.scrollRunwayBottom + 'px)';
//Clean Empty Nodes
while (this.unusednodes.length) {
this.unusednodes.pop().remove();
}
}
onScroll() {
scrollleft = this.scroller.scrollLeft;
scrolltop = this.scroller.scrollTop;
i = scrollleft - this.scrollLeft;
j = scrolltop - this.scrollTop;
if (i == 0 && j == 0) {
this.boundries[LEFT] = Math.max(0, Math.floor(scrollleft / this.cellWidth));
this.boundries[RIGHT] = Math.floor((scrollleft + this.scrollerWidth) / this.cellWidth);
j = 1;
}
if (Math.abs(i) > Math.abs(j)) {
this.boundries[LEFT] = Math.max(0, Math.floor(scrollleft / this.cellWidth));
this.boundries[RIGHT] = Math.floor((scrollleft + this.scrollerWidth) / this.cellWidth);
if (i > 0) {
//console.log("horizontal forward");
this.fillGrid(this.boundries[LEFT], this.boundries[RIGHT] + PREPOPULATION_COUNT, this.boundries[TOP], this.boundries[BOTTOM]);
} else if (i < 0) {
// console.log("hoirzontal backward");
this.fillGrid(Math.max(0, this.boundries[LEFT] - PREPOPULATION_COUNT), this.boundries[RIGHT], this.boundries[TOP], this.boundries[BOTTOM]);
}
} else if (Math.abs(i) < Math.abs(j)) {
this.boundries[TOP] = Math.max(0, Math.floor(scrolltop / this.cellHeight));
this.boundries[BOTTOM] = Math.floor((scrolltop + this.scrollerHeight) / this.cellHeight);
if (j > 0) {
// console.log("vertical forward");
this.fillGrid(this.boundries[LEFT], this.boundries[RIGHT], this.boundries[TOP], this.boundries[BOTTOM] + PREPOPULATION_COUNT);
} else if (j < 0) {
// console.log("vertical backward");
this.fillGrid(this.boundries[LEFT], this.boundries[RIGHT], Math.max(0, this.boundries[TOP] - PREPOPULATION_COUNT), this.boundries[BOTTOM]);
}
}
this.scrollLeft = scrollleft;
this.scrollTop = scrolltop;
}
getFreeNode() {
if (this.unusednodes.length) {
return this.unusednodes.pop();
}
return this.source.getTombstone();
}
}
class ContentSource {
constructor(row, col) {
this.no_of_columns = col;
this.no_of_rows = row;
this.row_height = 40;
this.column_width = 180;
this._cellnode = document.querySelector("#CELL_TEMPLATE");
}
getCellWidth() {
return this.column_width;
}
getCellHeight() {
return this.row_height;
}
getNumberOfRows() {
return this.no_of_rows;
}
getNumberOfColumns() {
return this.no_of_columns;
}
getCellCoordinates(row_id, col_id) {
return {
x: row_id == 0 ? 0 : (row_id) * this.row_height,
y: col_id == 0 ? 0 : (col_id) * this.column_width
};
}
getTombstone() {
return this._cellnode.content.cloneNode(true).firstElementChild;
}
render(div, row, col) {
div = div || this.getTombstone();
div.querySelector('.cell-content').textContent = row + '-' + col;
return div;
}
}
var source = new ContentSource(10000, 100);
window.scroller = new Grid(source, document.getElementById('grid'));
html,
body {
width: 100%;
height: 100%;
margin: 0;
}
/* Cell Common to All */
.cell {
position: absolute;
width: 180px;
height: 40px;
display: flex;
align-items: middle;
justify-content: flex-start;
border-right: 1px solid #e2e8f0;
border-bottom: 1px solid #e2e8f0;
/* border-radius:3px; */
text-align: center;
box-sizing: border-box;
contain: layout;
will-change: transform;
}
.cell-content {
padding: 10px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.cell[data-type='number'] {
justify-content: flex-end;
}
.cell[data-type='text'] {
justify-content: flex-start;
}
.cell[data-type='date'] {
justify-content: flex-end;
}
.grid {
margin: 0;
padding: 0;
overflow: scroll;
-webkit-overflow-scrolling: touch;
width: 100%;
height: 100%;
position: absolute;
box-sizing: border-box;
contain: layout;
will-change: transform;
border: 1px solid #e2e8f0;
}
<div id="grid" class='grid-class'></div>
<template id='CELL_TEMPLATE'>
<div class="cell" data-type='text'><span class='cell-content'>sample</span></div>
</template>