広告
Javascriptで画像の遅延読み込み(ライブラリなしで)

タグ:javascript

画像が多いページ、読み込みが遅くて困ることがありませんか?
私のサイトのイラストはまさしく画像が多くて遅くなっていました。
そこで画像が本当に必要になるまで読み込みを行わない遅延読み込みを実装しました。

遅延読み込みを使うことで
  • ページの表示時は必要な分だけ(表示範囲内だけなど)の画像を表示する
  • スクロールで表示すべき画像が増えたときに追加で読み込み
のようにしてページの表示速度を改善することができます。

実装の上では
  • HTMLには空のテーブルを置いておく。
  • 画面が埋まるまでテーブルに画像を入れる関数 (下のコードのaddItemsToFillHeight) を用意する。
  • スクロールを検知するごとにaddItemsToFillHeightを呼ぶ。
というような方針を取ります。
以下は実際のコードです。
<html><body>
  <table id="table"> <!-- このテーブルにjsからデータを入れる -->
  </table>

  <script>
    var table = document.getElementById("table");
    table.style.tableLayout = "fixed";
    var data = [
      [
        "ayame5.html",
        "./img/20200307_3_thumbnail.png",
        "関あやめ(☆5)",
      ],
      // ---表示用データのため中略 ---
    ];

    var ncols = 5;
    current_item_num = 0;

    // 画像をテーブルに追加
    function addItem()
    {
      if(current_item_num >= data.length)
        return;
      if(current_item_num % ncols == 0){
        row = table.insertRow( -1 );
        var th = document.createElement( 'th' );
        row.appendChild( th );
      }

      // テーブルにセルを追加
      var td = row.insertCell( -1 );
      td.pixelWidth = 120;
      td.width = "120px";
      td.height = "160px";
      td.style.verticalAlign = "top"

      // 画像を設定
      var thumb = document.createElement("a");
      v = data[current_item_num];
      thumb.href = v[0];
      var img = document.createElement("img");
      img.src = v[1];
      img.width = 100;
      img.height = 100;

      // 画像の周りのテキストなどを設定
      thumb.appendChild(img);
      td.appendChild(thumb);
      td.appendChild(document.createElement("br"));
      var link = document.createElement("a");
      link.href = v[0];
      var txt = document.createElement("div");
      txt.innerHTML = v[2];
      txt.style.overflow = "hidden";
      link.appendChild(txt);
      td.appendChild(link);
      current_item_num++;
    }

    // スクロールした分が埋まるまでaddItemを呼ぶ
    function addItemsToFillHeight()
    {
        cr = table.getBoundingClientRect();
        if(window.innerHeight + 100
          <= cr.bottom)
          return;
        for(i = 0; i < ncols; i++)
          addItem();
        setTimeout(addItemsToFillHeight, 10);
    }

    // スクロールを検知
    window.addEventListener('scroll', (e) =>
    {
        addItemsToFillHeight();
    });

    // ページ読み込み時にも初期表示用に一度だけデータを入れておく
    addItemsToFillHeight();

  </script>
</body></html>


テーブルに十分にアイテムが入ったかどうかの判定はテーブルのバウンディングボックス (テーブルが表示されている領域を座標で表したもの)とウィンドウが表示している領域を 比較することで行います。
コードでは実際に
table.getBoundingClientRect().bottom: テーブルの下部のy座標
window.innerHeight: ウィンドウがスクロール込みでページの高さのどこまでを表示しているか
の比較をl.65で行っています。

動いている様子はここで確認できます。
読み込んだ直後は下図のように5行しかテーブルに入っていませんが (注:行数はディスプレイのサイズに依存します)


スクロールしていくと下図のようにテーブルの行数が増えていることが見て取れます。