web 制作アニメーション備忘録 ②
前回の続きです。
ぜひ参考にしてください。
完成イメージ
ページをスワイプしたりクリックすることで、本のページがめくられるアニメーションです。ページを自由に追加したりもちろんめくったページを戻ることもできます。
レスポンシブにも対応しているので、若干字は小さくなりますが、スマホ画面でも自由に使うことができます。
⇧codepenで本のページめくり animation を探したときに
本のページを追加したり、削除したりが比較的容易でしたのでこちらを参考にしました。
Hammer.js 公式サイトを調べてみると以下のような記載がありました。
Hammer は、タッチ、マウス、ポインター イベントによるジェスチャーを認識できるオープン ソース ライブラリです。依存関係がなく、サイズも小さく、縮小 + gzip 圧縮してもわずか 7.34 kB です。
お使いのブラウザや OS がリストにない場合でも、問題なく動作する可能性があります。Internet Explorer 8 以前ではサポートされていません。
確かに、公式リファレンスを見てみると今回使用した Swipe オプションは全てのブラウザで対応しそうです。
他にも下記のオプションがあるようです。
今後気になったら調べてみようと思います。
タップ(tap): シングルタップを検出(クリックに似た動作)。
ダブルタップ(doubletap): 2 回連続でタップする動作を検出。
スワイプ(swipe): 指をスライドさせる動作を検出。方向(左、右、上、下)も認識可能。
パン(pan): スワイプに似ていますが、短いスライドではなく、長く指をスライドさせた動作を検出。
ピンチ(pinch): 2 本の指を使って拡大・縮小する操作を検出。
回転(rotate): 2 本の指で回転させる操作を検出。
コードの解説
- 必要なライブラリの読み込みと必要な画像の用意
ページの捲る部分の左側と右側の部分の切り抜きを全部で3枚準備する(自然にページを捲るため)
三枚目:
本全体の画像
<!-- Hammer.jsのCDN -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
Hammer.js はスワイプ操作の検出、jQuery は DOM 操作の簡略化に使用します。
- 初期設定とイベントリスナーの追加
コードをコピーする
document.addEventListener('DOMContentLoaded', function () {
var bookElement = document.querySelector('.book');
// Hammer.js のインスタンスを作成
var hammer = new Hammer(bookElement);
hammer.on('swipeleft', nextPage);
hammer.on('swiperight', prevPage);
Hammer.js で bookElement をスワイプできるようにし、左スワイプ (swipeleft) で次のページ、右スワイプ (swiperight) で前のページに移動します。
bookElement.addEventListener("click", function (event) {
if (event.target.closest(".active")) {
nextPage();
} else if (event.target.closest(".flipped:not(.initial)")) {
prevPage();
}
});
クリックされた要素が .active クラスを持っていれば nextPage() を実行し、次のページへ移動。
.flipped クラスがついていて、かつ .initial でない場合は prevPage() を実行し、前のページに戻ります。
前のページに戻る関数 prevPage()
function prevPage() {
// フリップされたすべてのページを取得
var lastFlipped = document.querySelectorAll(".flipped");
// 最後にフリップされたページ(最後にめくられたページ)を取得
var lastFlippedPage = lastFlipped[lastFlipped.length - 1];
// 最後のページが初期ページでない場合に処理を続行
if (!lastFlippedPage.classList.contains("initial")) {
// 最後のフリップされたページから `flipped` クラスを削除し、`active` クラスを追加(アクティブ状態に戻す)
lastFlippedPage.classList.remove("flipped");
lastFlippedPage.classList.add("active");
// 兄弟要素(現在のページ以外の要素)から `active` クラスを削除
var siblings = Array.prototype.filter.call(
lastFlippedPage.parentNode.children,
function (child) {
return child !== lastFlippedPage;
}
);
siblings.forEach(function (sibling) {
sibling.classList.remove("active");
});
}
}
最後にめくられたページをアクティブな状態に戻し、他のページから active クラスを削除します。
これにより、前のページが再度表示されるような動作になります。
- 次のページに進む関数
nextPage()
function nextPage() {
// 現在のアクティブなページ(現在表示中のページ)を取得
var activePage = document.querySelector(".active");
// 次のページが存在しないか、次の要素がページでない場合は関数を終了
if (
!activePage.nextElementSibling ||
!activePage.nextElementSibling.classList.contains("page")
) {
return;
}
// 現在のアクティブなページから `active` クラスを削除し、`flipped` クラスを追加(めくられた状態にする)
activePage.classList.remove("active");
activePage.classList.add("flipped");
// 次のページをアクティブページとして設定
var nextPage = activePage.nextElementSibling;
nextPage.classList.add("active");
// 兄弟要素(現在のページ以外の要素)から `active` クラスを削除
var siblings = Array.prototype.filter.call(
nextPage.parentNode.children,
function (child) {
return child !== nextPage;
}
);
siblings.forEach(function (sibling) {
sibling.classList.remove("active");
});
}
現在のページを「フリップされた」状態にし、次のページを「アクティブ」なページに設定します。
これにより、現在のページがめくられて次のページが表示されるような動作になります。
- 初期状態の設定
document.querySelector(".page").classList.add("flipped", "initial");
document.querySelector(".page:nth-of-type(2)").classList.add("active");
最初のページをフリップ状態 (flipped) と初期状態 (initial) にし、2 番目のページに active クラスを追加して表示されるようにします。
まとめ
この 2 つの関数により、nextPage() で次のページに進み、prevPage() で前のページに戻る動作が実現されています。これにより、ページをめくるような操作を簡単に実現でき、現在のページがどれなのかをクラスによって管理しています。