1
2

More than 3 years have passed since last update.

自身のポートフォリオに組み込んだ「アニメーションキュー」のご紹介

Posted at

はじめに

本記事は自身のポートフォリオに組み込んだ自作機能「アニメーションキュー」を紹介するものです。組み込みたい方はぜひ組み込んでみてください。

環境

npx create-nuxt-appを使用。(ver.2.0.0)

私の自作した「アニメーションキュー」とは?

文字通りアニメーションをキューにため込み、一つのアニメーションを実行、終了、次のアニメーションを実行、終了...を繰り返す機能です。
hogehoge.gif
こんな感じでスクロールに合わせて順番にアニメーションを実行するということが可能です。

アニメーションキューのイメージは以下の通りです。
Untitled Diagram.png
先に追加されたアニメーションから実行されるという至ってシンプルなシステムです。

本題

早速本題に入ります。
このシステムの流れとしては以下のとおりです。

  1. CSSでアニメーションを定義。
  2. VueXで、アニメーション登録の流れを定義。
  3. 各コンポーネントでアニメーションを実行したいdomにrefを設定し、mountedで実際にアニメーション登録。

CSSでアニメーション定義

ではまず、CSSから。
今回は簡単なフェードインを実装した。
assets内に以下のファイルを作成。


@keyframes scaleup-fadein{
  0%{
    opacity: 0;
    transform: scale(0.8);
  }
  100%{
    opacity: 1;
    transform: scale(1.0);
  }
}

これを作成したら、nuxt.config.jsのmodule.exportにてcss: [<作成したファイル名>]としてcssを共通のものに登録します。

VueX(store)に設定ファイルを作成

次にstoreディレクトリに以下のファイルを作成します。


export const state = () => ({
  //アニメーションを保管するキュー
  //オブジェクト型のため、セクションごとに別設定を行える。
  animeQue: {}
});

export const mutations = {
  /**
   * アニメーションをキューに追加する。
   * @param {*} state
   * @param {*} param1
   */
  pushAnime(state, { regist, anime, dom }) {
    // アニメーション開始前にDOMの不可視
    dom.style.opacity = "0";
  // アニメーション終了後にDOMの可視化状態を維持
    dom.addEventListener("animationend", function() {
      dom.style.opacity = "1";
    });

    //まだキューに何もない場合。
    if (state.animeQue[regist] === void 0) {
      // 新たなアニメーションキューを生成。
      state.animeQue[regist] = [];
      //スクロールがどの位置に来たら開始するかを設定する。
      if (anime.distance != void 0)
        window.addEventListener("scroll", function() {
          if (anime.distance > dom.getBoundingClientRect().top) {
            // 指定の位置まで来たため、アニメーションを実行する。
            dom.style.animationName = anime.name;
          }
        });
      // スクロール位置の設定がない場合はすぐにスタート
      else dom.style.animationName = anime.name;
    }

    //一つ以上のキューにある場合
    else {
      //キューの一番最後にアニメーションを追加し、
      //前のアニメーションが終了したら発動するよう設定する
      state.animeStack[regist][
        state.animeStack[regist].length - 1
      ].addEventListener("animationend", function() {
        dom.style.animationName = anime.name;
      });
    }
    // アニメーションの感覚時間を決定し、実際にプッシュ
    dom.style.animationDuration = anime.duration + "s";
    state.animeStack[regist].push(dom);
  }
};

これがアニメーションキューの本体です。

登録名ごとにアニメーションキューが生成されます。

また、アニメーションについて、
・ キューが生成された場合はアニメーションのスタートタイミングの設定(座標指定がコンポーネントからあった場合は設定し、指定がなければすぐ開始。)
・ キューに新たなアニメーションが追加された場合は、ひとつ前のアニメーションが終了されたときに追加したアニメーションが実行されるように設定。
という決まりになっています。

各コンポーネントでアニメーションキューの追加設定をする。

アニメーションを実施したいコンポーネントに設定することで、それぞれのアニメーションを順番に動かすことが可能です。

コード例は以下の通りです。


<template>
  <h2 ref="secondTitle" class="second-title">
    <span class="second-title-frame"></span>
    <span class="second-title-frame"></span>
    <span class="second-title-frame"></span>
    <span class="second-title-frame"></span>

    <span class="title">{{ title }}</span>
    <span class="subtitle">{{ subtitle }}</span>
  </h2>
</template>

<script>
export default {
  props: {
    title: String,
    subtitle: String,
    animeregist: String,
  },
  mounted() {
    this.$store.commit("anime/pushAnime", {
      regist: this.animeregist,
      anime: {
        name: "scaleup-fadein",
        duration: 0.3,
        distance: 600,
      },
      dom: this.$refs.secondTitle,
    });
  },
};
</script>

mountedにてアニメーションキューに登録をしている。storeにanime.jsという名前で保存したためcommit先がanime/pushAnimeとなっています。
commitしているオブジェクト詳細については以下のとおりです。

{
  regist : "アニメーションキュー名/string",
  anime:{
    name:"アニメーション名(CSSで設定したアニメーション)/string"
    duration:"アニメーションの実行期間/double"
    distance:"アニメーションを開始する際のスクロール座標/int"
  },
  dom:"指定するDOM/DOMElement"
}

今回の場合だとSecondTitleというコンポーネントであるため、propsにてアニメーションキューの情報を受け取ることとし、pagesで実際の値を渡すようにしています。
こうすることで、同じコンポーネントを使っていても別々のアニメーションキューに登録することが可能であります。

最後に

どうでしょう。使い道はありそうでしょうか。すでに既出な気もしますが、自身で1から作ってみたため、本記事で紹介してみました。ぜひシステムに組み込んでみてください。

本記事に対して、わかりづらい等のご意見あれば、お待ちしております。

では皆様、また会いましょう。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2