preface
In daily development, we mostly use paging or lazy loading for lists with large data. But now there’s a need to show 100,000 pieces of data on the front end. How do you do that? We all know that too much DOM leads to page lag, but is there a way to fix it? Of course, it is a virtual scroll list. So what is a virtual scroll list? How does it work? You can think of it simply as dynamically rendering a list of visual area data. I wrote a simple demo of the Angular CDK virtual scroll list implementation. If you are interested, don’t miss it. Without further ado, get right to the code.
implementation
Schematic diagram
CSS
* {
margin: 0;
padding: 0;
}
.virtual-scroll-viewport {
position: relative;
width: 240px;
height: 300px;
margin: 150px auto 0;
overflow: auto;
will-change: scroll-position;
border: 1px solid #aaaaaa;
}
/* Open height */
.virtual-scroll-spacer {
position: absolute;
top: 0;
left: 0;
right: 0;
}
.virtual-scroll-list {
position: absolute;
top: 0;
left: 0;
right: 0;
}
.virtual-scroll-item {
height: 50px;
padding-left: 15px;
line-height: 50px;
}
.virtual-scroll-item:nth-child(2n) {
background: #f6f8fa;
}
Copy the code
HTML
<div class="virtual-scroll-viewport">
<div class="virtual-scroll-spacer"></div>
<div class="virtual-scroll-list"></div>
</div>
Copy the code
JS
/ / get the dom
const virtualViewportDom = document.querySelector('.virtual-scroll-viewport');
const virtualSpacerDom = document.querySelector('.virtual-scroll-spacer');
const virtualListDom = document.querySelector('.virtual-scroll-list');
const VIEWPORT_HEIGHT = 300; // Viewport height
const ITEM_HEIGHT = 50; // List item height
const COUNT = 10; // Number of renders
const TOTAL_COUNT = 100000; / / the total number of article
const TOTAL_HEIGHT = ITEM_HEIGHT * TOTAL_COUNT; / / total height
let scrollTop = 0, translateY = 0;
virtualSpacerDom.style.height = TOTAL_HEIGHT + 'px';
// Listen for scroll events
virtualViewportDom.addEventListener('scroll'.function (e) {
scrollTop = this.scrollTop;
const start = Math.max(Math.floor(scrollTop / ITEM_HEIGHT) - 2.0);
const end = Math.min(start + COUNT, TOTAL_COUNT);
const y = start * ITEM_HEIGHT;
if (scrollTop === 0 || scrollTop === TOTAL_HEIGHT - VIEWPORT_HEIGHT || Math.abs(translateY - y) >= 100) {
render(start, end);
translateY = y;
virtualListDom.style.transform = 'translate3d(0px, ' + translateY + 'px, 0px)'; }});// First render
render(0, COUNT);
function render(start, end) {
let html = ' ';
// Remove the extra DOM
let list = document.querySelectorAll('.virtual-scroll-item');
for (const item of list) {
const index = Number(item.dataset.index);
if (index < start || index >= end) {
item.remove();
}
}
list = document.querySelectorAll('.virtual-scroll-item');
if (list.length > 0) {
const lastStart = Number(list[0].dataset.index);
const lastEnd = Number(list[list.length - 1].dataset.index);
if (end - 1 - lastEnd > 0) { / / decline in
for (let i = lastEnd + 1; i < end; i++) {
html += '<div class="virtual-scroll-item" data-index="' + i + '">item' + i + '</div>';
}
virtualListDom.insertAdjacentHTML('beforeend', html);
} else if (start - lastStart < 0) { / / slide
for (let i = start; i < lastStart; i++) {
html += '<div class="virtual-scroll-item" data-index="' + i + '">item' + i + '</div>';
}
virtualListDom.insertAdjacentHTML('afterbegin', html); }}else {
// Quickly slide or drag the scrollbar or render for the first time
for (let i = start; i < end; i++) {
html += '<div class="virtual-scroll-item" data-index="' + i + '">item' + i + '</div>'; } virtualListDom.innerHTML = html; }}Copy the code
Demo: jsdemo. Codeman. Top/HTML/virtua…
conclusion
At this point, we have implemented a simple virtual scrolling list. However, there are still some shortcomings, such as:
- List items are not dynamic heights
- A quick swipe on mobile devices and some browsers will give you a brief blank space