はじめに
ウェブサイトでギャラリーや商品紹介などを行う際、複数の画像をスライドショー形式で表示するモーダルは非常に有効です。今回は、Swiperライブラリを使用して複数のスライド可能なモーダルを実装し、各モーダル内の特定のスライドを直接開く方法を解説します。
HTML構造
まず、モーダルを開くためのトリガー要素とモーダル自体のHTML構造を見てみましょう。
トリガー要素
<div class="masonry-container masonry-viewModalTmb">
<ul id="gallery-1" class="masonry-wrapper">
<li class="masonry-slide">
<a class="masonry-ifield js-opnr4KVA" data-opento="sdl-peji4KVA">
<picture class="masonry-thumbnail">
<img src="画像のURL" alt="">
</picture>
</a>
</li>
<!-- 他のスライド -->
</ul>
</div>
モーダル本体
<dialog id="sdl-peji4KVA" class="swiper-container swiper-viewModal">
<ul class="swiper-wrapper">
<li class="swiper-slide">
<a class="swiper-ifield">
<picture class="swiper-thumbnail">
<img src="画像のURL" alt="">
</picture>
<div class="swiper-caption">
<h4 class="swiper-title">Image:01</h4>
</div>
</a>
</li>
<!-- 他のスライド -->
</ul>
<ol class="swiper-pagination"></ol>
<nav class="swiper-navigation">
<a class="swiper-button-prev" aria-label="Previous slide"></a>
<a class="swiper-button-next" aria-label="Next slide"></a>
</nav>
<a class="swiper-closer js-clsr4KVA" aria-label="閉じる">×</a>
</dialog>
ポイント:
- トリガー要素には
data-opento属性を使用して、開くべきモーダルのIDを指定します。 - モーダル本体は
<dialog>タグを使用し、Swiperの構造に従っています。 - 各モーダルに一意のIDを付与します(例:
id="sdl-peji4KVA")。
JavaScript実装
次に、モーダルとSwiperを制御するJavaScriptのコードを見ていきます。
(function () {
const swipOpnrs = Array.from(document.querySelectorAll(".js-opnr4KVA"));
const swipClsrs = Array.from(document.querySelectorAll(".js-clsr4KVA"));
const { body } = document;
let timer4KVA = 0;
let promiseSwpModal4KVA = function () {
if (timer4KVA) clearTimeout(timer4KVA);
timer4KVA = setTimeout(() => {
return new Promise(function (resolve, reject) {
setTimeout(function () {
// トリガー要素にdata-slideto属性を付与
const modalGroups = {};
swipOpnrs.forEach((swipOpnr) => {
const modalId = swipOpnr.getAttribute('data-opento');
if (!modalGroups[modalId]) {
modalGroups[modalId] = [];
}
modalGroups[modalId].push(swipOpnr);
});
Object.values(modalGroups).forEach((group) => {
group.forEach((swipOpnr, index) => {
swipOpnr.setAttribute('data-slideto', index + 1);
});
});
resolve();
}, 0);
})
.then(function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
// Swiperの初期化
let swipCtnrs = Array.from(document.querySelectorAll("dialog.swiper-container.swiper-viewModal"));
const swiperInstances = {};
swipCtnrs.forEach((tgtCtnr) => {
const modalId = tgtCtnr.id;
swiperInstances[modalId] = new Swiper(tgtCtnr, {
// Swiper設定
});
// キャンセルイベントの処理
tgtCtnr.addEventListener('cancel', () => {
tgtCtnr.classList.remove('is-opened');
body.classList.remove('is-modaled');
});
});
// モーダルを開く処理
swipOpnrs.forEach((swipOpnr) => {
swipOpnr.addEventListener('click', function (e) {
e.preventDefault();
const modalId = this.getAttribute('data-opento');
const tgtCtnr = document.getElementById(modalId);
const swiper = swiperInstances[modalId];
if (tgtCtnr && swiper) {
const dataSlideTo = this.getAttribute('data-slideto');
const intSlideTo = parseInt(dataSlideTo) || 1;
swiper.slideTo(intSlideTo);
tgtCtnr.showModal();
tgtCtnr.classList.add('is-opened');
body.classList.add('is-modaled');
}
});
});
// モーダルを閉じる処理
swipClsrs.forEach((swipClsr) => {
swipClsr.addEventListener('click', function (e) {
e.preventDefault();
const tgtCtnr = this.closest('dialog');
if (tgtCtnr) {
tgtCtnr.close();
tgtCtnr.classList.remove('is-opened');
body.classList.remove('is-modaled');
}
});
});
resolve();
}, 0);
});
})
.catch(function (error) {
console.log(error);
});
}, 300);
};
// イベントリスナーの設定
['load', 'resize'].forEach((events) => {
window.addEventListener(events, promiseSwpModal4KVA);
});
imagesLoaded(swipOpnrs, function (e) {
promiseSwpModal4KVA();
});
})();
実装のポイント
- モーダルグループの管理:
- 各モーダルに対応するトリガー要素をグループ化し、
data-slideto属性を付与します。これにより、各モーダル内の特定のスライドを直接開くことができます。
- Swiperインスタンスの管理:
- 各モーダルのIDをキーとして、Swiperインスタンスを管理するオブジェクトを作成します。これにより、複数のモーダルを個別に制御できます。
- モーダルを開く処理:
- トリガー要素のクリック時に、対応するモーダルとSwiperインスタンスを特定し、指定されたスライドを表示します。
- モーダルを閉じる処理:
- 閉じるボタンのクリックとキャンセルイベント(Escキー)の両方に対応します。
- 遅延処理とPromise:
setTimeoutとPromiseを使用して、DOM操作や初期化を適切なタイミングで実行します。
- リサイズ対応:
- ウィンドウのリサイズイベントに対応し、レイアウトの変更に対応します。
- 画像の読み込み完了後の処理:
imagesLoadedライブラリを使用して、画像の読み込みが完了した後に初期化処理を実行します。
まとめ
この実装により、複数のSwiperモーダルを持つページで、各モーダル内の特定のスライドを直接開くことができます。<dialog>タグとSwiperライブラリを組み合わせることで、アクセシビリティと使いやすさの両面で優れたUIを提供できます。
実際の使用時には、パフォーマンスの最適化(画像の遅延読み込みなど)やエラーハンドリングの強化を検討するとよいでしょう。また、CSSを適切に設定し、モーダルの見た目や動きを調整することで、よりユーザーフレンドリーなインターフェースを作成できます。
