IntersectionObserver  学習

Drupal 開発で IntersectionObserver が使われていましたが理解が追いつかなかった..。
(まず JS 自体そんな理解できてない)

今回は一旦整理したいので Drupal を無視して学習しました。

## IntersectionObserver とは

交差状態の変化を非同期に監視する方法を提供してくれるもの

## メリット

### 非同期処理

IntersectionObserverは非同期で動作し、ブラウザが最適なタイミングで監視対象の要素の可視性を判定します。スクロールイベントの頻繁な発生を避け、効率的なリソース利用が可能です。スクロールのたびに発生するイベントが少ないため、処理のオーバーヘッドが低減します。

### 複数の要素を一括して処理

IntersectionObserverは一度に複数の要素を監視できます。これにより、単一のイベントハンドラで複数の要素の可視性を処理できます。

### ビューポート外の要素を無視

IntersectionObserverは要素がビューポートに入っていない場合はその要素を無視します。スクロールイベントではビューポートに関係なく発生しますが、IntersectionObserverは実際に表示されている領域に焦点を当てるため、ビューポート外の要素に関しては処理の対象外となります。

## やること
- 画像をふわっと表示

## ファイルの準備
practice ディレクトリ化にファイル作成します。

```
practice
   |-index.html
   |-style.css
   |-observer.js
```
Codepen では rootMargin が上手く機能しなかったので、ローカルのほうが良さそうです。

### index.html
head タグ内でスタイルシートとJSファイルを読み込みます。

```html
<head>
  <link rel="stylesheet" href="style.css">
  <script src="observer.js" defer></script>
</head>
<body>
  <h1>テストだよ</h1>

  <img src="https://baconmockup.com/500/400" alt="">
  <img src="https://baconmockup.com/500/400" alt="">
  <img src="https://baconmockup.com/500/400" alt="">
  <img src="https://baconmockup.com/500/400" alt="">
  <img src="https://baconmockup.com/500/400" alt="">
  <img src="https://baconmockup.com/500/400" alt="">
  <img src="https://baconmockup.com/500/400" alt="">
  <img src="https://baconmockup.com/500/400" alt="">
  <img src="https://baconmockup.com/500/400" alt="">
</body>
```

### style.css
JS で付与する `.is-show` で表示制御。
`opacity`と`transition`で表示をふわっとさせます。

```css
img {
  display: block;
  max-width: 100%;
  height: auto;
  opacity: 0;
  transition: opacity 3s;
}
img.is-show {
  opacity: 1;
  transition: opacity 3s;
}
```

### observer.js

```js
// 全ての img を取得し変数に入れる.
const sections = document.querySelectorAll("img");

let options = {
  // viewport を指定できる.今回はデフォルト.
  root: null,
  // 監視中の要素がどんだけ viewport 内に入っているか.
  // 0.5 は 50% 入ったらイベント発火.
  threshold: 0.5,
  // viewport の範囲を大きくしたり小さくしたりできる.
  // 上下に 100px ずつ広がっている状態.
  rootMargin: "100px 0px 100px 0px",
};

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    // isIntersecting プロパティで監視中の要素が viewport に入っているかどうか判断できる.
    if(entry.isIntersecting) {
      // entry.target で要素にアクセスできる.
      // viewport に入ったら is-show を付与する.
      entry.target.classList.add("is-show");
    } else {
      // viewport の外に出たらクラスを削除.
      entry.target.classList.remove("is-show");
    }
  })
// 第２引数に設定したオプション.
}, options);

// 複数監視したいときは forEach で繰り返し処理.
sections.forEach(section => {
  // observe() メソッドを呼び出して処理を実行.引数には監視対象の要素が入る
  observer.observe(section);
});
```

とりあえずそれっぽく作ってみましたが、
`const observer = new IntersectionObserver((entries) => {`
辺りがよくわからん..。第２引数もやたら遠くて理解に苦しんだ。
↓
第１引数を分けてみました。

```js
// img 取得と options の記載は省略.
const observer = new IntersectionObserver(huwatto, options);

function huwatto(entries) {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add("is-show");
    } else {
      entry.target.classList.remove("is-show");
    }
  });
}

sections.forEach(section => {
  observer.observe(section);
});
```

こっちの方がわかりやすそうです。
これを Drupal で実装してみようと思います。
またいつか。

## 参考にしたサイト
- MDN : https://developer.mozilla.org/ja/docs/Web/API/Intersection_Observer_API  
- わかりやすかった動画 : https://www.youtube.com/watch?v=T8EYosX4NOo