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:

  1. List items are not dynamic heights
  2. A quick swipe on mobile devices and some browsers will give you a brief blank space