100,000 個のデータの高性能レンダリング: タイム スライス、仮想リスト、遅延読み込み

大量のデータを高性能でレンダリング

大量のデータのレンダリングには、タイム スライスと仮想リスト処理を使用できます

タイムスライス

簡単な理解は、データを多くの部分に分割し、それらをバッチでレンダリングすることです。ページ ジャンクは、多数の DOM を同時にレンダリングするために利用可能なタイム スライスが原因です。

方法 1 :setTimeout
短所: ただし、ページをすばやくスクロールすると、ページにスプラッシュ スクリーンまたは白いスクリーンがあることがわかります。

//需要插入的容器
let ul = document.getElementById('container');
// 插入十万条数据
let total = 100000;
// 一次插入 20 条
let once = 20;
//总页数
let page = total/once
//每条记录的索引
let index = 0;
//循环加载数据
function loop(curTotal,curIndex){
    
    
    if(curTotal <= 0){
    
    
        return false;
    }
    //每页多少条
    let pageCount = Math.min(curTotal , once);
    setTimeout(()=>{
    
    
        for(let i = 0; i < pageCount; i++){
    
    
            let li = document.createElement('li');
            li.innerText = curIndex + i + ' : ' + ~~(Math.random() * total)
            ul.appendChild(li)
        }
        loop(curTotal - pageCount,curIndex + pageCount)
    },0)
}
loop(total,index);

方法 2 :requestAnimationFrame + DocumentFragment

//需要插入的容器
let ul = document.getElementById('container');
// 插入十万条数据
let total = 100000;
// 一次插入 20 条
let once = 20;
//总页数
let page = total/once
//每条记录的索引
let index = 0;
//循环加载数据
function loop(curTotal,curIndex){
    
    
    if(curTotal <= 0){
    
    
        return false;
    }
    //每页多少条
    let pageCount = Math.min(curTotal , once);
    window.requestAnimationFrame(function(){
    
    
        let fragment = document.createDocumentFragment();
        for(let i = 0; i < pageCount; i++){
    
    
            let li = document.createElement('li');
            li.innerText = curIndex + i + ' : ' + ~~(Math.random() * total)
            fragment.appendChild(li)
        }
        ul.appendChild(fragment)
        loop(curTotal - pageCount,curIndex + pageCount)
    })
}
loop(total,index);

仮想リスト

仮想リストの実現は、実際には最初の画面がロードされたときに可視領域に必要なリスト項目のみをロードすることです. スクロールが発生すると、可視領域のリスト項目は計算によって動的に取得され、非可視領域のメモリのリスト項目が削除されます。

1. 現在の表示可能領域の開始データ インデックス (startIndex) を計算します。
2. 現在の表示可能領域の終了データ インデックス (endIndex) を計算します。
3. 現在の表示可能領域のデータを計算し、ページにレンダリングします
。リスト全体のオフセット位置 startOffset 内の startIndex に対応するデータをリストに設定します
ここに画像の説明を挿入

<!-- 虚拟列表 -->
  <div class="box">
    <!-- 内容真实高度 即200条数据的高度-->
    <div class="content-area" id="contentArea">
      <ul></ul>
    </div>
  </div>
	let el = document.querySelector(".box");
    let itemHeight = 110; //每个元素的高度(li的高度100 + marginBottom 10)
    let pageSize = Math.ceil(el.clientHeight / itemHeight); // 获取一个滚动屏最大可容纳子元素个数(向上取整)
    let data = []; //mock数据
    let startIndex = 0; //可视区第一行下标
    let endIndex = pageSize; //可视区最后一行下标

    // 初始化模拟数据
    let getData = () => {
    
    
      for (let i = 0; i < 200; i++) {
    
    
        data.push({
    
    
          content: `我是显示的内容${
      
      i + 1}`,
        });
      }
    };

    // 加载数据并插入到dom页面
    let loadData = () => {
    
    
      let html = "";
      let sliceData = data.slice(startIndex, endIndex);
      for (let i = 0; i < sliceData.length; i++) {
    
    
        html += `
            <li class="item">
              <p>${
      
      sliceData[i].content}</p>
            </li>`;
      }
      el.querySelector("#contentArea ul").innerHTML = html;
    };

    // 更新DOM
    let updateHtml = () => {
    
    
      let sliceData = data.slice(startIndex, endIndex);
      let itemAll = el.querySelectorAll(".item");
      for (let i = 0; i < sliceData.length; i++) {
    
    
        itemAll[i].querySelector("p").innerHTML = sliceData[i].content;
      }
    };

    // 滑动监听
    el.addEventListener("scroll", function () {
    
    
      let scrollTop = el.scrollTop; // 滚动高度
      startIndex = Math.ceil(scrollTop / itemHeight); // 重新计算开始的下标,div顶部卷起来的长度除以列表元素的高度
      endIndex = startIndex + pageSize;
      updateHtml(); // 重新更新dom
      el.querySelector("#contentArea ul").style.transform =
        "translateY(" + startIndex * itemHeight + "px)";
    });

    let init = () => {
    
    
      getData();
      loadData();
      document.getElementById("contentArea").style.height =
        itemHeight * data.length + "px"; // 占位dom的高度
    };

    // 页面初始化调用
    init();

遅延読み込み

あまり紹介せず、1 文の説明: 最初はすべてのデータがレンダリングされず、ビューに表示されているデータのみが表示され、ページの下部までスクロールすると、さらにデータが読み込まれます

実装原理:親要素のスクロールイベントをリッスンすることはもちろん、IntersectionObserverやgetBoundingClientRectなどのAPIで実装することも可能

ただし、スクロールイベントが頻繁に発生するため、手動で調整する必要があります; スクロール要素には DOM が多く、フリーズしやすいため、IntersectionObserver を使用することをお勧めします

おすすめ

転載: blog.csdn.net/qq_38110274/article/details/127527148