質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
87.20%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

解決済

画像モーダルでprev, next ボタンが機能しない

erp
erp

総合スコア45

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

1回答

0評価

0クリップ

358閲覧

投稿2022/01/07 23:45

編集2022/01/08 06:49

前提・実現したいこと

画像モーダルで、画像をdata-group でグループ化したいです。

発生している問題・エラーメッセージ

今のところ、開いた画像と同じ data-group に class="on" をつけるところまではできました。
onモーダルの prev, next ボタンを押すと、グループ化された on のついた画像を一つずつ移動(+1, -1)するようにしたいです。

ところが、現状では最初の一回のボタンの押下で +3, -3 されてしまう状態です。ボタンを何回も押せば本来のように +1, -1ずつ動きますが、安定して増減させたいです。

該当のソースコード

js

document.addEventListener('DOMContentLoaded', function () { class Modal { constructor() { //初期値(DOM) this.DOM = {}; this.DOM.html = document.querySelector('html'); this.DOM.thumbItems = document.querySelectorAll('.modal-imgs'); this.DOM.modal = document.querySelector('.modal-wrapper'); this.DOM.modalOverlay = document.querySelector('.modal-overlay'); this.DOM.modalItem = document.querySelector('.mid'); this.DOM.modalCaption = document.querySelector('.modal-aside'); this.DOM.modalClose = document.querySelector('.mp-close'); this.DOM.modalPrev = document.querySelector('.mp-prev'); this.DOM.modalNext = document.querySelector('.mp-next'); // スワイプ座標 this.startX; this.endX; // ターゲット要素 this.thumbTarget; // 何番めの要素か this.thumbCurrent; // 最初に実行する関数 this._init(); } _init() { this.DOM.thumbItems.forEach((thumbItem, index, array) => { thumbItem.addEventListener('click', this._appearModal.bind(this, thumbItem, index)); }); this._clickEvent(); // this._swipeEvent(); // this._mouseEvent(); } // クリックイベント _clickEvent() { this.DOM.modalClose.addEventListener('click', this._disappearModal.bind(this)); this.DOM.modalOverlay.addEventListener('click', this._disappearModal.bind(this)); this.DOM.modal.addEventListener('click', (e) => { if (e.target.querySelector('.modal-img')) { this._disappearModal.bind(this); } }); this.DOM.modalNext.addEventListener('click', this._next.bind(this)); this.DOM.modalPrev.addEventListener('click', this._prev.bind(this)); } // モーダル表示 _appearModal(thumbItem, index) { this.DOM.html.classList.add('is-fixed'); this.thumbCurrent = index; // 現在のindex this.DOM.modal.classList.add('spinner'); this.DOM.modal.classList.add('show'); this.DOM.modalOverlay.classList.add('show'); this.thumbTarget = thumbItem; //モーダル表示する要素 this._modalShow(this.thumbTarget); // モーダル表示 setTimeout(function () { document.querySelector('.modal-wrapper').classList.remove('spinner'); }, 200); } // モーダル非表示 _disappearModal() { this.DOM.html.classList.remove('is-fixed'); this.DOM.modal.classList.remove('show'); this.DOM.modalOverlay.classList.remove('show'); this.DOM.thumbItems.forEach(function (thumbItem) { thumbItem.classList.remove('on'); }); } // モーダルに表示する画像 _modalShow(self) { const imgElm = self; const targetModalItem = this.DOM.modalItem.childNodes[0]; targetModalItem.src = imgElm.getAttribute('data-src'); // フェードインのクラス targetModalItem.classList.remove('show'); setTimeout(function () { targetModalItem.classList.add('show'); }, 300); // グループ化 imgElm.classList.add('on'); let imageGroup = imgElm.getAttribute('data-group'); this.DOM.thumbItems.forEach(function (thumbItem) { if (thumbItem.getAttribute('data-group') === imageGroup) { thumbItem.classList.add('on'); } }); this._modalCaption(imgElm); } // モーダルに表示するキャプション _modalCaption(imgElm) { this.DOM.modalCaption.innerText = imgElm.dataset.caption } _next() { this.DOM.modal.classList.add('spinner'); const thumbItemsOn = document.querySelectorAll('.modal-imgs.on'); this.thumbCurrent = this._changeCount(1, this.thumbCurrent, thumbItemsOn.length); this.thumbTarget = thumbItemsOn[this.thumbCurrent]; this._modalShow(this.thumbTarget); // モーダル表示 setTimeout(function () { document.querySelector('.modal-wrapper').classList.remove('spinner'); }, 200); } _prev() { this.DOM.modal.classList.add('spinner'); const thumbItemsOn = document.querySelectorAll('.modal-imgs.on'); this.thumbCurrent = this._changeCount(-1, this.thumbCurrent, thumbItemsOn.length); this.thumbTarget = thumbItemsOn[this.thumbCurrent]; setTimeout(function () { document.querySelector('.modal-wrapper').classList.remove('spinner'); }, 200); this._modalShow(this.thumbTarget); // モーダル表示 } // 変更する番号を取得 _changeCount(num, index, len) { return (index + num + len) % len; } } // インスタンス化 const modal = new Modal(); });

html

<!-- gallery --> <div class="img-fit-01"> <div class="aspect-box spinner"> <img alt class="lazyload modal-imgs" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" style="width: 100%; height: 100%;" data-group="gallery-01" data-src="img/photo/04.png" data-caption="画像の詳細を書けます 01-01"> </div> <div class="aspect-box spinner"> <img alt class="lazyload modal-imgs" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" style="width: 100%; height: 100%;" data-group="gallery-01" data-src="img/photo/04.png" data-caption="画像の詳細を書けます 01-02"> </div> <div class="aspect-box spinner"> <img alt class="lazyload modal-imgs" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" style="width: 100%; height: 100%;" data-group="gallery-01" data-src="img/photo/04.png" data-caption="画像の詳細を書けます 01-03"> </div> <div class="aspect-box spinner"> <img alt class="lazyload modal-imgs" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" style="width: 100%; height: 100%;" data-group="gallery-01" data-src="img/photo/04.png" data-caption="画像の詳細を書けます 01-04"> </div> <div class="aspect-box spinner"> <img alt class="lazyload modal-imgs" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" style="width: 100%; height: 100%;" data-group="gallery-01" data-src="img/photo/04.png" data-caption="画像の詳細を書けます 01-05"> </div> <div class="aspect-box spinner"> <img alt class="lazyload modal-imgs" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" style="width: 100%; height: 100%;" data-group="gallery-01" data-src="img/photo/04.png" data-caption="画像の詳細を書けます 01-06"> </div> <aside>モーダルサンプル 02 / data-group でグループ化</aside> </div> <!-- image modal --> <div class="modal-wrapper spinner"> <div class="mid"><img alt src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></div> <div class="mp-prev"></div> <div class="mp-next"></div> <div class="mp-close"></div> <aside class="modal-aside">xxx</aside> </div> <div class="modal-overlay"></div>

css

.modal-overlay { display: none; position: fixed; align-items: center; justify-content: center; flex-direction: column; top: 0; left: 0; cursor: pointer; z-index: -1; opacity: 0; background: rgba(255, 255, 255, 1); transition: all .25s 0s ease; } .modal-overlay.show { display: flex; width: 100%; height: 100%; z-index: 4; opacity: 1; } .modal-wrapper { display: flex; position: fixed; align-items: center; justify-content: center; flex-direction: column; transform: translate(-50%, -50%); top: 50%; left: 50%; z-index: -1; visibility: hidden; opacity: 0; transition: visibility .25s, opacity .25s; pointer-events: none; } .modal-wrapper.show { width: auto; z-index: 10; visibility: visible; opacity: 1; pointer-events: all; } .mid img { display: inline-block; position: relative; max-width: 80vw; max-height: 80vh; margin: 0; z-index: 5; opacity: 0; transition: .5s ease-out; -webkit-animation: show; animation: show; pointer-events: all; } .mid img.show { opacity: 1; -webkit-animation: show 1.3s ease-in-out; animation: show 1.3s ease-in-out; }

試したこと

js

_next() { this.DOM.modal.classList.add('spinner'); const thumbItemsOn = document.querySelectorAll('.modal-imgs.on'); this.thumbCurrent = this._changeCount(1, this.thumbCurrent, thumbItemsOn.length); this.thumbTarget = thumbItemsOn[this.thumbCurrent]; this._modalShow(this.thumbTarget); // モーダル表示 } _prev() { this.DOM.modal.classList.add('spinner'); const thumbItemsOn = document.querySelectorAll('.modal-imgs.on'); this.thumbCurrent = this._changeCount(-1, this.thumbCurrent, thumbItemsOn.length); this.thumbTarget = thumbItemsOn[this.thumbCurrent]; this._modalShow(this.thumbTarget); // モーダル表示 }

ここがうまく動いていないのだとおもいます。
試しに、

js

_next() { this.thumbCurrent = this._changeCount(1, this.thumbCurrent, this.DOM.thumbItems.length); this.thumbTarget = this.DOM.thumbItems[this.thumbCurrent]; this._modalShow(this.thumbTarget); // モーダル表示 } _prev() { this.thumbCurrent = this._changeCount(-1, this.thumbCurrent, this.DOM.thumbItems.length); this.thumbTarget = this.DOM.thumbItems[this.thumbCurrent]; this._modalShow(this.thumbTarget); // モーダル表示 }

としたところ、うまく +1, -1 されました。
また、コンソールに以下のようにすると、

js

console.log(thumbItemsOn); console.log(thumbItemsOn.length);

画像はきちんと取れていました。

js

this.thumbCurrent = this._changeCount(1, this.thumbCurrent, thumbItemsOn.length);

ここがうまく +1, -1 できていないのかと思うのですが、どう変更すればいいのか全くお手上げです。

どうかご助力をお願いできませんでしょうか。なにとぞよろしくお願いいたします。

補足情報(FW/ツールのバージョンなど)

Firefox 最新版

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

まだ回答がついていません

会員登録して回答してみよう

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
87.20%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。