BETA

JavaScript で Intersection Observer API を使って要素が表示されているか調べる

投稿日:2020-05-22
最終更新:2020-05-22

はじめに

JavaScript で Intersection Observer API を使って要素がビューポート内に表示されているか調べた。

概略

(async () => {  
  /**  
   * @param {Element} elem  
   */  
  const isDisplaying = (elem) => {  
    return new Promise((r) => {  
      const iObserver = new IntersectionObserver(([{ isIntersecting }]) => {  
        r(isIntersecting);  
        iObserver.unobserve(elem);  
      });  
      iObserver.observe(elem);  
    });  
  };  

  console.log(  
    await Promise.all(  
      [...document.body.querySelectorAll('*')].map(async (elem) => ({  
        elem,  
        isDisplaying: await isDisplaying(elem),  
      })),  
    ),  
  );  
})();  

詳細

Intersection Observer API とは

スクロールによって要素(Element)がビューポート(ブラウザの表示領域)の端と「交差」するのを監視する API。
画像などの遅延読み込みや無限スクロールなどが簡単に実装できる。

↓ 簡単な使い方

<!DOCTYPE html>  
<html lang="ja">  
  <head>  
    <meta charset="UTF-8" />  
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />  
    <title>Intersection Observer API Demo</title>  

    <style>  
      #targetTop,  
      #targetBottom {  
        border: 1px solid black;  
      }  
    </style>  
  </head>  
  <body>  
    <div id="targetTop">  
      <p>#targetTop</p>  
    </div>  
    <div>  
      <p>適当なスペース</p>  
      <p>適当なスペース</p>  
      <p>適当なスペース</p>  
      <p>適当なスペース</p>  
      <p>適当なスペース</p>  
      <p>適当なスペース</p>  
      <p>適当なスペース</p>  
      <p>適当なスペース</p>  
      <p>適当なスペース</p>  
      <p>適当なスペース</p>  
    </div>  
    <div id="targetBottom">  
      <p>#targetBottom</p>  
    </div>  

    <script>  
      document.addEventListener('DOMContentLoaded', () => {  
        const $targetTop = document.getElementById('targetTop');  
        const $targetBottom = document.getElementById('targetBottom');  

        const iObserver = new IntersectionObserver((changes) => {  
          for (const change of changes) {  
            console.log(change);  
          }  
        });  
        iObserver.observe($targetTop);  
        iObserver.observe($targetBottom);  
      });  
    </script>  
  </body>  
</html>  

ウィンドウサイズを小さくした上でスクロールしてみてほしい。
#targetTop#targetBottomが画面に映ったり映らなくなったりするたびに callback が実行されIntersectionObserverEntryconsole.logされる。

Promise で同期的に扱えるようにする

Promiseresolveを callback 内で呼び出すことで、awaitを使って同期的にIntersectionObserverEntryを得ることができるようにした。

概略のところでは、Promise.allを使って Web ページのbodyより下にあるすべての要素について一気に調べている。

おわりに

少し邪道な気もする。
この API は実験的であるため動作が変更されるかもしれない(まぁでも IE 以外では動くしもう大丈夫でしょ)。

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

おかゆりぞっとのさほど技術的ではないブログ

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう