白いくま  | Lab  | Blog  | About

IntersectionObserverをカスケード

Updated: 5/14/2022 Original: 8/18/2020

Javascript coding

要素が範囲内に現れたかどうかを判定するのに便利なIntersectionObserver。だけど、このObserverが要素にゴニョゴニョした後にその要素の中の別要素をnew IntersectionObserverでまたなんとかしようとしてつまづきました。

例えばですね、こんなケースです。

  • 親要素(targetA)はビューポートの中段に来た頃にフェードイン

  • その後、targetA内にあるtargetBがビューポートの上端に達したらなんか発動

みたいなときです。結果的には、並列に書いちゃだめで、入れ子で作らなきゃいけないってことでした。簡略化しまくったのでこのままでは動きませんが、要は次のようなイメージです。

const observerA = new IntersectionObserver((entriesA) => {
  entriesA.forEach(entryInA => {
    if (entryInA.isIntersecting) {
      /* DO SOMETHING FOR targetA using entryInA*/

      /* Add observer for targetB */
      const observerB = new IntersectionObserver(
        (entriesB) => {
          /*DO SOMETHING FOR targetB using entriesB*/
        }, {});
      observerB.observe(entryInA.target.querySelector("#targetB"));

      /* remove observer not to duplicate */
      observerA.unobserve(entry.target);
    }
  });
}, {});
observerA.observe(document.querySelector('#targetA'));

observerAとobserverBは順番付けとかないと全然反応してくれないんですね。随分と時間を食ってしまいました、とほほ。

追記(8/25):loadのイベントリスナー内に入れたら大丈夫でした。結構普通な解決になってしまった。

//code for targetA, then:

window.addEventListener("load",()=>{
  const targetB = document.querySelectorAll('.targetB');
  const handlerB = (entries) => {
    entries.forEach(e => {
      //do something for targetB elements
    });
  };
  const observerB = new IntersectionObserver(handlerB, {
    //options
  });
  targetB.forEach(b => {
    observerB.observe(b);
  });
},false);

https://developer.mozilla.org/ja/docs/Web/API/Intersection_Observer_API/Timing_element_visibility