observer = new IntersectionObserver はいくつも作れます!

コーディング練習でPhotoshopカンプからのコーディングを練習していたときに、 少し悩みました。 でも、よく考えたら、ふつうにつくれるでしょうということのような気もしますが、 ぼくの勉強も含めて記事にしようと思いました。

やりたかったこと

1つのページの中で、交差オブザーバーを使って、以下の2つを付けたいと思いました。

  • ある程度スクロールしてきたらヘッダー出現
  • スクロールに合わせて、タイトルや画像が入ってくる、よくあるやつ

最初にヘッダーの出現をIntersectionObseverを使って実装していました。 その後、スクロールに合わせてのアニメーションはお手軽なAOSにしようとしました。 すると、まだきちんと確認していないのですが、競合してしまっているような感じがしました。 なので、すべてのアニメーションをIntersectionObseverを使おうとしました。

ちがうアニメーションをつけたい。

ということで、オブザーバーのインスタンス(?)を2つ作りたいなと思ったのですが、 ふと、 「2つ作っても大丈夫なのか?」と 疑問に感じたので、調べてみようと思い立ったしだいです。

検索してみた

「IntersectionObsever 複数」などで検索すると 「複数要素を監視」の記事が多くて、Observerインスタンスを2つ作れるのか、 複数のインスタンスを作って、違うコールバック関数を使いたいという例が出てきません。

でも、よくよく考えてみれば、 インスタンスなのだから、いくつか作っても全くOKってあとで気づいた次第です。

解決して書いたコード

// ヘッダーが現れるときのアクション
// これはある程度スクロールしたらクローンのヘッダーが上からスライドダウンしてくるアニメーションを付けています。
const options = {
  rootMargin: "80%",
  threshold: 1.0,
};
const headerObserver = new IntersectionObserver((entries) => {
  entries.forEach((e) => {
    if (!e.isIntersecting) {
      headerClone.classList.add("clone-open");
    }
    if (e.isIntersecting) {
      headerClone.classList.remove("clone-open");
    }
  });
}, options);
headerObserver.observe(mv);

// タイトルアニメーション
// これは各セクションのタイトルが見えたら、左からシュッと入ってくるアニメーション
const titleObserver = new IntersectionObserver((entries) => {
  entries.forEach((e) => {
    if (e.isIntersecting && !e.target.classList.contains('slideLeft')) {
      console.log(e.target);
      e.target.classList.add("slideLeft");
    }
  });
});
const animateTitles = document.querySelectorAll('.c-section__heading-block');
animateTitles.forEach((t)=>{
    titleObserver.observe(t);
})

// 画像のアニメーション
// いくつかの画像に下からシュッと出現するアニメーション
const imageObserver = new IntersectionObserver((entries)=>{
    entries.forEach((e)=>{
        if (e.isIntersecting && !e.target.classList.contains('fadeUp')) {
      console.log(e.target);
      e.target.classList.add("fadeUp");
    }
    })
})
const animateImages = document.querySelectorAll('.js-animate-image');
animateImages.forEach((t)=>{
    console.log(t.target);
    imageObserver.observe(t);
})

今後のこと

パフォーマンス的にどうなのだろうかというところは今後の課題。 Obseverインスタンスを1つにして、 その中のコールバック関数で、 要素の種類に応じて、違うアニメーションをつけるとかいう方法もあるのだろうか、 とかぼんやり考えています。