#交差点オブザーバー

Web ページを開発するとき、要素が「ビューポート」(ビューポート) に入っているかどうか、つまりユーザーがそれを見ることができるかどうかを知る必要があることがよくあります。

上の図の緑色の四角形がスクロールし、その可視性が上部に示されます。

従来の実装方法は、scroll をリッスンした後、ターゲット要素 (緑の四角形) の getBoundingClientRect() を呼び出すことです。 getBoundingClientRect) メソッドを使用して、ビューポートの左上隅に対応する座標を取得し、それがビューポート内にあるかどうかを判断します。この方法の欠点は、「スクロール」イベントが集中的に発生するため、計算量が非常に多くなり、[パフォーマンスの問題]が発生しやすいことです(http://www.ruanyifeng.com/blog/2015/09) /web-page-performance-in - Depth.html)。

IntersectionObserver API は、要素が Chrome 51 以降で既にサポートされているかどうかを自動的に「監視」できます。可視の本質は、ターゲット要素とビューポートが交差領域を作成することであるため、この API は「交差オブザーバー」と呼ばれます。

導入

IntersectionObserver API の使用法は 2 行だけです。

varobserver = new IntersectionObserver(コールバック, オプション);
オブザーバー.オブザーブ(ターゲット);

上記のコードでは、IntersectionObserver はブラウザーによってネイティブに提供されるコンストラクターであり、2 つのパラメーターを受け入れます。 callback は可視性が変更されたときのコールバック関数であり、option は設定オブジェクトです (このパラメーターはオプションです)。

IntersectionObserver() の戻り値はオブザーバー インスタンスです。インスタンスの observe() メソッドは、どの DOM ノードを監視するかを指定できます。

// 観察を開始する
observer.observe(document.getElementById('example'));

// 観察をやめる
オブザーバー.unobserve(要素);

// オブザーバーを閉じる
オブザーバー.切断();

上記のコードでは、「observe()」のパラメータは DOM ノード オブジェクトです。複数のノードを観察したい場合は、このメソッドを複数回呼び出す必要があります。

観察者.観察(要素A);
観察者.観察(要素B);

IntersectionObserver API は非同期であり、ターゲット要素のスクロールと同期的にトリガーされないことに注意してください。仕様では、IntersectionObserver の実装では requestIdleCallback() を使用する必要があると規定されています。つまり、オブザーバーはスレッドがアイドル状態のときにのみ実行されます。これは、このオブザーバーの優先度が非常に低く、他のタスクが完了し、ブラウザーが空いている場合にのみ実行されることを意味します。

IntersectionObserver.observe()

IntersectionObserver インスタンスの observe() メソッドは、DOM 要素の監視を開始するために使用されます。このメソッドは、コールバック関数 callback と設定オブジェクト options の 2 つのパラメータを受け入れます。

コールバックパラメータ

ターゲット要素の可視性が変化すると、オブザーバーのコールバック関数 callback が呼び出されます。

callback は 2 回トリガーされます。 1 回目はターゲット要素がビューポートに入ったばかりのとき (表示され始めたとき)、もう 1 回はターゲット要素が完全にビューポートから出たとき (非表示になり始めたとき) です。

var オブザーバー = 新しい IntersectionObserver(
  (エントリ、オブザーバー) => {
    console.log(エントリ);
  }
);

上記のコードでは、コールバック関数は [arrow function](http://es6.ruanyifeng.com/#docs/function#arrow function) の形式で記述されています。 callback 関数のパラメータ (entries) は配列であり、各メンバーは IntersectionObserverEntry オブジェクトです。 (詳細は以下を参照してください)。たとえば、2 つの観測オブジェクトの可視性が同時に変化する場合、entries 配列には 2 つのメンバーが含まれます。

IntersectionObserverEntry オブジェクト

IntersectionObserverEntry オブジェクトはターゲット要素に関する情報を提供し、合計 6 つのプロパティを持ちます。

{
  時間: 3893.92rootBounds: ClientRect {
    下: 920、
    高さ: 1024、
    左: 0、
    右: 1024、
    上: 0、
    幅:920
  }、
  boundingClientRect: ClientRect {
     // ...
  }、
  IntersectionRect: ClientRect {
    // ...
  }、
  交差点比率: 0.54、
  ターゲット: 要素
}

各属性の意味は以下のとおりです。

  • time: 可視性が変化する時刻。ミリ秒単位の高精度タイムスタンプです。
  • target: 監視されているターゲット要素は DOM ノード オブジェクトです
  • rootBounds: コンテナ要素の長方形領域に関する情報、getBoundingClientRect() メソッドの戻り値、コンテナ要素がない場合 (つまり、ビューポートに対して直接スクロールしている場合)、null が返される
  • boundingClientRect: 対象要素の長方形領域に関する情報
  • intersectionRect: ターゲット要素とビューポート(またはコンテナ要素)の間の交差領域に関する情報
  • intersectionRatio: 対象要素の可視比率、つまり intersectionRectboundingClientRect の比率 完全に可視である場合は 1 であり、0 以下になります。完全に見えなくなったとき。

上の図では、灰色の水平ボックスはビューポートを表し、濃い赤色の領域は観測された 4 つのターゲット要素を表します。それぞれの「intersectionRatio」の数値が記録されています。

IntersectionObserverEntry オブジェクトをデモするために、デモ を作成しました。このデモは Chrome 51 以降でのみ実行できることに注意してください。

オプションオブジェクト

IntersectionObserver コンストラクターの 2 番目のパラメーターは構成オブジェクトです。以下のプロパティを設定できます。

(1)閾値属性

threshold 属性は、コールバック関数がいつトリガーされるか、つまり、要素がどの割合でビューポート (またはコンテナ要素) に入ったときにコールバック関数が実行されるかを決定します。これは配列であり、各メンバーはしきい値であり、デフォルトは [0] です。つまり、交差比率 (intersectionRatio) が 0 に達するとコールバック関数がトリガーされます。

「threshold」プロパティが 0.5 の場合、要素がビューポートの 50% に入ったときにコールバック関数がトリガーされます。値が [0.3, 0.6] の場合、要素が 30% および 60% に入ったときにコールバック関数がトリガーされます。

newIntersectionObserver(
  エントリ => {/* … */}、
  {
    しきい値: [00.250.50.751]
  }
);

ユーザーはこの配列をカスタマイズできます。たとえば、上記の例の [0, 0.25, 0.5, 0.75, 1] は、ターゲット要素 0%、25%、50%、75%、100% が表示されたときにコールバック関数がトリガーされることを意味します。

(2) ルート属性、rootMargin 属性

IntersectionObserver は、ビューポートを基準とした要素の可視性だけでなく、要素が含まれるコンテナを基準とした要素の可視性も観察できます。コンテナ内でのスクロールは、ターゲット要素の可視性にも影響します。この記事の冒頭の図を参照してください。

IntersectionObserver API は、コンテナ内のスクロールをサポートします。 root 属性は、ターゲット要素が配置されているコンテナ ノードを指定します。コンテナ要素はターゲット要素の祖先ノードである必要があることに注意してください。

var opts = {
  ルート: document.querySelector('.container')、
  ルートマージン: '0px 0px -200px 0px'
};

var オブザーバー = 新しい IntersectionObserver(
  折り返し電話、
  選択します
);

上記のコードには、「root」属性に加えて、rootMargin 属性もあります。このプロパティは、「rootBounds」四角形のサイズを拡大または縮小するために使用され、それによって「intersectionRect」交差領域のサイズに影響します。書き方はCSSの「margin」属性に似ており、「0px 0px 0px 0px」のように上下左右の4方向の値を表します。

上記の例の「0px 0px -200px 0px」は、コンテナの下端が上に 200 ピクセル縮小し、ページが表示されたときにターゲット要素の上部が 200 ピクセルの表示領域に入った後でのみコールバック関数がトリガーされることを意味します。下にスクロールされます。

この設定後は、ウィンドウ内でスクロールしているかコンテナ内でスクロールしているかに関係なく、ターゲット要素の可視性が変化する限り、オブザーバーがトリガーされます。

遅延ロード

場合によっては、ユーザーが下にスクロールしてビューポートに入ったときにのみ、特定の静的リソース (画像など) を読み込む必要があります。これにより、帯域幅が節約され、Web ページのパフォーマンスが向上します。これを「遅延読み込み」と呼びます。

IntersectionObserver API を使用すると、これを簡単に実装できます。画像のHTMLコードは以下のように記述できます。

<img src="placeholder.png" data-src="img-1.jpg">
<img src="placeholder.png" data-src="img-2.jpg">
<img src="placeholder.png" data-src="img-3.jpg">

上記のコードでは、画像はデフォルトでプレースホルダーを表示し、「data-src」属性は遅延ロードされる実際の画像です。

関数クエリ(セレクター) {
  return Array.from(document.querySelectorAll(selector));
}

var オブザーバー = 新しい IntersectionObserver(
  関数(エントリ) {
    エントリ.forEach(関数(エントリ) {
      エントリー.ターゲット.src = エントリー.ターゲット.データセット.src;
      オブザーバー.unobserve(entry.target);
    });
  }
);

query('.lazy-loaded').forEach(function (item) {
  観察者.観察(項目);
});

上記のコードでは、実際の画像ファイルは、画像が表示されるときにのみロードされます。

無限スクロール

無限スクロールとは、Web ページが一番下までスクロールするときに、ページに新しいコンテンツを継続的に読み込むことを指します。その実装も非常に簡単です。

var IntersectionObserver = 新しい IntersectionObserver(
  関数 (エントリ) {
    // 表示されない場合は戻ります
    if (entries[0].intersectionRatio <= 0) が戻る;
    ロードアイテム(10);
    console.log('ロードされた新しいアイテム');
  }
);

// 観察を開始する
IntersectionObserver.observe(
  document.querySelector('.scrollerFooter')
);

無限にスクロールする場合、上記の例のように、ページの下部にフッター バー (センチネル とも呼ばれます。上の例は .scrollerFooter) を配置するのが最善です。フッター バーが表示されると、ユーザーがページの下部に到達したことを示し、新しい項目を読み込んでフッター バーの前に配置できるようになります。それ以外の場合、新しいコンテンツがページに追加されるたびに、observe() メソッドを呼び出して、新しいコンテンツの下部に監視を確立する必要があります。

ビデオは自動的に再生されます

以下はビデオ要素で、ビューポートに完全に入ったときに自動的に再生され、ビューポートから出たときに自動的に一時停止するようにしたいと考えています。

<ビデオ src="foo.mp4" コントロール=""></ビデオ>

以下はJSコードです。

let video = document.querySelector('video');
isPaused = false;

let オブザーバー = new IntersectionObserver((エントリ, オブザーバー) => {
  エントリ.forEach(エントリ => {
    if (entry.intersectionRatio != 1 && !video.paused) {
      video.pause();
      isPaused = true;
    else if (isPaused) {
      video.play();
      isPaused=false;
    }
  });
}, {しきい値: 1});

観察者.観察(ビデオ);

上記のコードでは、IntersectionObserver() の 2 番目のパラメーターは構成オブジェクトであり、その threshold プロパティは 1 に等しくなります。つまり、ターゲット要素が完全に表示されたときにコールバック関数がトリガーされます。

参考リンク


作者: wangdoc

アドレス: https://wangdoc.com/

ライセンス: クリエイティブ・コモンズ 3.0