Back

IntersectionObserverを使用したシンプルなアニメーション制御をComposition APIでやるには

IntersectionObserverを使用したシンプルなアニメーション制御をComposition APIでやるには

これは、Qiita Vue Advent Calendar 2023の20日目の記事です。

こんにちは、keigo です。今回は、画面スクロールによって要素が表示されたタイミングで、アニメーションを発火させるための実装を紹介します。

以下のようなものです。 画面スクロールによって要素が表示されたタイミングでアニメーションが発火するgif

IntersectionObserverとは

IntersectionObserverは、JavaScript APIのひとつです。 特定の要素がビューポート(ブラウザの表示領域)とどのように交差しているかを非同期的に監視するものです。

ref: https://developer.mozilla.org/ja/docs/Web/API/IntersectionObserver

特定の要素がスクロールによって画面に描画されたタイミングで、特定の処理を発火させる

Vue3のComposition APIで実現するためには、以下のようなコードを書いていきます。

はじめに、イベント検出対象の要素に、ref属性を付与します。

<div ref="hoge" class="good-vibes-class">

そして、上記で付与したref属性の要素を取得し、onMountedでIntersectionObserverを呼び出します。

const hoge = ref(); // 付与したref属性と同じ名前で宣言する

const handleIntersect = (entries: IntersectionObserverEntry[]) => {
  if (entries[0].isIntersecting) {
    // スクロールによって要素が描画されたとき
  } else {
    // 要素が描画されていないとき
  }
}

onMounted(() => {
  const observer = new IntersectionObserver(handleIntersect, {
    root: null,
    rootMargin: '0px',
    threshold: 0
  });

  if (hoge.value) {
    observer.observe(hoge.value);
  }
})

アニメーションをつけるには

アニメーション対象の要素のcssに、transitionプロパティを付与します。

例:

.good-vibes-class {
  transition: all 0.5s ease;
}

こうすることで、.good-vibes-classにスタイルの変更が発生した場合は、0.5秒かけて変化過程が描画されます。

script側でスタイルを変更させるには、以下のように記述することで可能です。

const hoge = ref(); // 付与したref属性と同じ名前で宣言する
const animationTarget = document.getElementsByClassName('good-vibes-class');

const handleIntersect = (entries: IntersectionObserverEntry[]) => {
  if (entries[0].isIntersecting) {
    // 要素が画面に描画されると、横幅が0pxから100pxになる
    (animationTarget[0] as HTMLElement).style.width = '100px';
  } else {
    (animationTarget[0] as HTMLElement).style.width = '0px';
  }
}

onMounted(() => {
  const observer = new IntersectionObserver(handleIntersect, {
    root: null,
    rootMargin: '0px',
    threshold: 0
  });

  if (hoge.value) {
    observer.observe(hoge.value);
  }
})

おわりに

IntersectionObserverを使用することで、要素が画面に描画されているかどうかを監視することができます。アニメーションのみならず、JavaScriptで発火可能な処理ならなんでも可能です。 どなたかの参考になれば幸いです!