はじめに
本記事は自身のポートフォリオに組み込んだ自作機能「アニメーションキュー」を紹介するものです。組み込みたい方はぜひ組み込んでみてください。
環境
npx create-nuxt-app
を使用。(ver.2.0.0)
私の自作した「アニメーションキュー」とは?
文字通りアニメーションをキューにため込み、一つのアニメーションを実行、終了、次のアニメーションを実行、終了...を繰り返す機能です。
こんな感じでスクロールに合わせて順番にアニメーションを実行するということが可能です。
アニメーションキューのイメージは以下の通りです。
先に追加されたアニメーションから実行されるという至ってシンプルなシステムです。
本題
早速本題に入ります。
このシステムの流れとしては以下のとおりです。
- CSSでアニメーションを定義。
- VueXで、アニメーション登録の流れを定義。
- 各コンポーネントでアニメーションを実行したい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から作ってみたため、本記事で紹介してみました。ぜひシステムに組み込んでみてください。
本記事に対して、わかりづらい等のご意見あれば、お待ちしております。
では皆様、また会いましょう。