LoginSignup
1
2

More than 5 years have passed since last update.

要素が表示されたら〜をIntersectionObserverで実現する

Posted at

表題の通りですが、簡単なメモを残しておきます。

要件

  • 要素がビューに入った際に1度だけ処理が走る
  • 画面描画時に既に要素が表示されている場合は処理を即実行させる
  • クロスブラウザに対応させる

対応ブラウザは以下を参照
IntersectionObserver/polyfill

デモ

jsdo.itconsole.log吐いてるだけなのでわかりづらいですね・・・)

解説

以下のjavascriptを3段階に分けて解説していきます。
また、polifillはrawgitを使用して読み込んでいます。
※rawgitについては【個人メモ】rawgithub(CDN)のサービスがアップデートされてたを参考にしました。

var intersectionObserver = new IntersectionObserver(function(entries) {
    // target is out of view
    if (entries[0].intersectionRatio <= 0) return;

    // one time firing
    intersectionObserver.unobserve(entries[0].target);

    // some functions...
    fn(entries[0].target);
});

var elements = document.querySelectorAll('.block');
Array.prototype.forEach.call(elements, function (elm) {
    if (elm.getBoundingClientRect().top <= window.innerHeight) {
        // target is already displayed
        fn(elm);  
    } else {
        intersectionObserver.observe(elm);
    }
});

function fn(target) {
    console.log('entered the view: ' + target.className);
}

インスタンス生成

var intersectionObserver = new IntersectionObserver(function(entries) {
    // target is out of view
    if (entries[0].intersectionRatio <= 0) return;

    // one time firing
    intersectionObserver.unobserve(entries[0].target);

    // some functions...
    fn(entries[0].target);
});

ここではインスタンスを生成し、要素がビューを出入りした際の処理をコールバックで書いています。
中に3つの処理を書いていますが、それぞれ

  • 1つ目:要素が外に出た際には処理しない
  • 2つ目:一度処理が走ったら以降処理しない
  • 3つ目:何かしらの処理を外部関数で行う

という感じになっています。
entries[0].targetにイベントが発生した要素が入っていますので、これを外部関数fnに渡しています。

インスタンスに要素を渡す

var elements = document.querySelectorAll('.block');
Array.prototype.forEach.call(elements, function (elm) {
    if (elm.getBoundingClientRect().top <= window.innerHeight) {
        // target is already displayed
        fn(elm);  
    } else {
        intersectionObserver.observe(elm);
    }
});

今回は.blockという要素が複数あることを想定しています。
Array.prototype~とやっているのは、querySelectorAllで取得できるのがNodeListという配列に似た何か(表現雑・・・)で、ChromeだとそのままforEachで回ったりするのですが、確かIEだとエラー出るのでその回避のための記述です。

この中で行っている条件分岐は、要素が既に表示されていたら(既にビューを超えて画面上部に消えている場合も含む)というもので、trueなら外部関数を即実行、falseならインスタンスに要素を渡す、としています。

外部関数

function fn(target) {
    console.log('entered the view: ' + target.className);
}

この外部関数は、observerから呼ばれるものと要素が既に表示されていたら〜から呼ばれる共通の関数です。
引数、内容はそれぞれの要望に合わせて変更してください。

おわりに

javascriptの進化半端ない

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2