HTML / API / Intersection Obserer

HTML / API / Intersection Obserer

【注意】ここにある情報は筆者の理解が浅い、もしくは検証環境がおかしいため嘘の情報が含まれている可能性が高いです。参考にしないでください。

ブラウザの可視範囲に入ったら何かするやつ jQuery を使わなくても簡単にできる。

まず使ってみる

var options = {
    root: document.querySelector('#piyo'),
    rootMargin: "10px",
    threshold: 1.0
}
var observer = new IntersectionObserver(function(entries, observer) { 
    entries.forEach(entry => {
        if(entry.isIntersecting){
            console.log("hogehoge");
        }
    });
}, options);
var targetList = document.querySelectorAll("#piyo .hoge");
for(let target of targetList){
    observer.observe(target);
}

オプション

これがオプション

var options = {
    root: document.querySelector('#hoge'),
    rootMargin: 0,
    threshold: 1.0
}

root

root は監視対象を内包するオブジェクトを指す。 このオブジェクトのサイズが表示されたとみなす範囲になる。 指定なしは画面全体(つまり普通に画面で見えている範囲全体)を指す。

これは単一の DOM である必要がある、(querySelectorAllで取得するような)複数の要素を一気に指定することはできない。

ではどのような場合にこの指定するかというと、

#hoge{
    height: 100px;
    over-flow: auto;
}

のように要素の中身の表示が意図的に限定されている場合に設定する。つまり疑似フレームみたいな状況。

この場合は高さは 100px で限定されているので内容物が 100px 以上ある場合その部分が切れて表示される。 auto に指定してあるので、その部分はスクロールバーが出てスクロール可能状態になっている。 そのスクロールでスクロールさせて、その切れて見えなくなってる部分が表示されたら発火する。

rootMargin

root を実際の範囲よりどの程度デカくみなすか。

デカくみなすとは実際に表示されるよりも手前でイベントが発火する。 画像の先行ロード等で表示してからでは間に合わないみたいな場合に若干大きめの値を設定する。

デフォルトは 数値0px でも指定できる。その場合は文字列で指定する。

threshold

対象の要素がどの程度見える状態になるとイベントが発火するかを設定する。 1 は対象が内に完全に入った場合に発火、0.5 なら半分、0 だと入る直前に発火する。

IntersectionObserver を作る

名前の通り「監視者」を作る。

var observer = new IntersectionObserver(function(entries, observer) { 
    entries.forEach(entry => {
        if(entry.isIntersecting){
            console.log("hogehoge");
        }
    });
}, options);

コールバック関数

第一引数にコールバック関数を取る。このコールバックは内部の監視対象が表示の条件に合致したら呼び出される。 どの監視対象が合致しても呼び出される。

呼び出しタイミング

このコールバック関数は大きく3つのタイミングで呼び出される。

  • observe メソッドで何かが登録されてそれを監視開始する直後
    • observe メソッドは複数回連続で呼ばれることが普通で、連続で呼び出すとその塊が1個として発火する
    • どのように分割して呼び出すと塊が分かれるのかはよくわからない
    • タイミングをずらして observe を登録するとそのタイミングでも発火する
  • 画面表示条件が合致する直後のタイミング
  • 画面表示条件が合致しなくなった直後のタイミング

こいつは表示しているしていないではなく交差を見ているのでこのようなタイミングで発火する 交差を見ているのでそいつが画面上にモノとして見えているかどうかは関係ない

第1引数

コールバックの第1引数には監視対象を付加情報でラップしたモノが渡される。 この監視対象はタイミングによってちょっと渡されるモノが変化するので注意する必要がある。

まず↑に示した登録して一発目の監視開始時は無条件で全登録対象が entries に入ってくる。 しかしタイミングをズラした場合はそのズラした監視対象だけ入ってくる。 observe したタイミングで無条件で対象に対して1回実行されるとおぼえておけば良い。

そして次からは監視対象でそれが交差した対象が入ってくる。 状況によってはここに2つ同時に入ってくる可能性もある。

intersectionRatio

普通に監視対象に対してイベントが発火するタイミングは(最初の登録時を除いて)2回ある。 対象が条件を満たす瞬間と、条件から外れる瞬間である。

0.8 指定してた場合ならば、スクロールして 80% 入った瞬間に発火し、次に 100% になりさらにスクロールして、画面から外れて 80% になる瞬間に発生する。

ここで要素の画面割合が上昇側で入ったのか減少側で入ったのかを測る必要がある。 これが intersectionRatio でイベントが発火したタイミングでの対象の画面要素表示割合を示してくれる。

仕様には明示されてないが、表示割合が上昇するタイミングでは threshold よりも若干大きな値になり、画面割合が下降するタイミングでは threshold よりも若干小さな値になるようだ。

これを基準に2回発火するイベントを使い分けることができるだろう。

殆どの場合において上昇側(画面に対象のある範囲が表示され続けるタイミング)で何かやりたいことがほとんどだと思うので threshold < intersectionRatio のタイミングで何かやればいいだろう。

第2引数 監視者

これは単に監視者。

observe 監視対象を登録

observe メソッドで監視対象を監視者へ登録する。

var targetList = document.querySelectorAll("#piyo .hoge");
for(let target of targetList){
    observer.observe(target);
}

監視対象を特録するのが、これがいつのタイミングで開始されるのかがまったくわからない。 監視を停止するメソッドはあるが、逆に復帰するメソッドは無い。 監視対象を登録したタイミングでは無いようだ。

注意

height: 100vh のような状態で threshold: 1.0 指定してそのような要素が連続していると、 スクロールの最小単位の関係でピッタリ入った瞬間に出ていくという動作になることが多く、思った瞬間が捉えられないことがある。

なので threshold: 0.8 のように気持ち小さい値を入れておくとよい。

Tags

html/api/intersection_obserer.txt · 最終更新: 2021-11-25 17:09 by ore