Intersection Observerでスクロールアニメーションをつくってみる

#はじめに
今までスクロールに連動した処理を実装するときは、jQueryの`scroll`イベントを使ってきました。
しかし上記の処理だとスクロールの度に実行され、パフォーマンスに影響を及ぼすことがあります。

今回は`Intersection Observer API`を使い、より効率的なスクロール連動アニメーションをつくってみました。

#Intersection Observer API (交差監視 API) とは
> *ターゲットとなる要素が、祖先要素もしくは文書の最上位のビューポートと交差する変更を非同期的に監視する方法を提供します。*
https://developer.mozilla.org/ja/docs/Web/API/Intersection_Observer_API

つまり、これを使うと**スクロールして特定の位置にきた時のみ**に処理を実行できます。

`scroll`イベントではブラウザ幅の変更で特定の位置が変わった際に、`resize`処理を考える必要がありました。
Intersection Observerは**viewportの変更で要素の位置が変わっても自動的に反応します。**
スクロールの度に処理が実行されることがないので、パフォーマンス的にも良いとされてます。

#つくってみた
<p class="codepen" data-height="265" data-theme-id="default" data-default-tab="js,result" data-user="hitsujiball" data-slug-hash="OJPMNob" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Scroll_Animation">
  <span>See the Pen <a href="https://codepen.io/hitsujiball/pen/OJPMNob">
  Scroll_Animation</a> by M_H (<a href="https://codepen.io/hitsujiball">@hitsujiball</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

```JavaScript:JavaScript
/**
* スクロールアニメーション
*/
const _setScrollAnime = () => {
  const sectionPos = document.querySelectorAll('.js-sec-target'); // 監視対象の要素

  // IntersectionObserverのオプション設定
  const options = {
    root: null,
    rootMargin: '-50% 0px',
    threshold: 0.5
  };

  // IntersectionObserverを呼び出す
  const observer = new IntersectionObserver(anchorSetting, options);
  
  // ターゲット（sectionPos）を監視する
  for(let p = 0; p < sectionPos.length; p++) {
    (function() {
      observer.observe(sectionPos[p]);
    })();
  }

 // 要素が交差する度（スクロール位置がターゲットに到達する度）に _setCurrent関数 を呼び出す
 function anchorSetting(entries) {
    for(let i = 0; i < entries.length; i++) {
      (function() {
        if(entries[i].isIntersecting) {
          _setCurrent(entries[i]);
        }
      })();
    }
  };
  
  // div.anime に .is-currentクラス を付与する関数
  const _setCurrent = (target) => {
    //.is-currentクラス が付与された要素を取得
    const currentIndex = document.querySelector('.js-anime.is-current');

    // currentIndex に .is-currentクラス が付いていたら削除（初期化）
    if(currentIndex !== null) {
      currentIndex.classList.remove('is-current');
    }

    // 現在地の div.anime に .is-currentクラス を付与
    const currentNew = document.querySelector(`.${target.target.children[1].classList[1]}`);
    currentNew.classList.add('is-current');
  };
};

_setScrollAnime();
```

##作り方
1. `section.js-sec-target`がブラウザの高さ50%までスクロールしたら、`_setCurrent()`を実行します。
![alt](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183513/192eb1de-e34c-edf3-0f7a-cce87b2a4ef8.png)
2. `div.anime`（グレーの正方形）に`.is-current`クラスを付与します。（※アニメーションはCSS側で実装しました。）
![alt](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183513/ae6a022c-245d-5ef1-ddac-cc9cd9f979b5.png)

##注意点
###IE11はポリフィルが必要
IE11はIntersectionObserverに対応していないので、ポリフィルを追加する必要があります。
https://github.com/w3c/IntersectionObserver/tree/master/polyfill

#感想
今回はスクロールアニメーションを作りましたが、他にも画像の遅延読み込みやグロナビのカレント表示など、様々な場面で活躍しそうだなと思いました。
パフォーマンスを考慮したコーディングができるよう、恐れず積極的に使ってみたいです。

#参考サイト
以下を参考にさせていただきました。
https://developer.mozilla.org/ja/docs/Web/API/Intersection_Observer_API
https://ics.media/entry/190902/