はじめに
- JavaScript 上でmodal 表示のためのイベント処理を書いていたところ、コードの重複が多くなってしまい、なんとか短くできるか試行錯誤した結果、自分なりに短くすることができたのでその記録のため書きたい。
- 他に効率の良い書き方とかあったら教えて欲しい....
やったこと
- 複数ある同じオブジェクト上のボタンを追加すると、モダルで前のオブジェクトの情報を反映する別のオブジェクトを表示させる
- JavaScript で元のオブジェクトの情報を引数として渡す
最初のコード
複数あるカードとボタン全てイベントを追加した後、引数のイベントのターゲットごとに Switch statement で一個一個のシナリオを書いた結果、重複が多く、コードの量が多くなった。
<!-- 元々表示するカード群 -->
<!-- 便宜上もろもろ省く -->
<div class="card-wrapper">
<div class="card">
<h1 class="card-title">Card Title</h1>
<button id="card-1-btn" class="card-btn">Check</button>
</div>
<div class="card">
<h1 class="card-title">Card Title</h1>
<button id="card-2-btn" class="card-btn">Check</button>
</div>
<div class="card">
<h1 class="card-title">Card Title</h1>
<button id="card-3-btn" class="card-btn">Check</button>
</div>
<div class="card">
<h1 class="card-title">Card Title</h1>
<button id="card-4-btn" class="card-btn">Check</button>
</div>
<div class="card">
<h1 class="card-title">Card Title</h1>
<button id="card-5-btn" class="card-btn">Check</button>
</div>
</div>
<!--上記カード上のボタンが押されたら表示されるモダル群-->
<!-- Card modal -->
<div id="modal-1" class="modal">
<!-- modal content -->
<div class="modal-content">
<span id="modal-close-1" class="modal-close">×</span>
<div class="modal-text">
<p class="modal-paragraph">
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Voluptas,
cum?Lorem ipsum dolor sit amet consectetur adipisicing elit.
</p>
</div>
</div>
</div>
<div id="modal-2" class="modal">
<!-- modal content -->
<div class="modal-content">
<span id="modal-close-1" class="modal-close">×</span>
<div class="modal-text">
<p class="modal-paragraph">
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Voluptas,
cum?Lorem ipsum dolor sit amet consectetur adipisicing elit.
</p>
</div>
</div>
</div>
<!--...以下省略 -->
// 全てのモダルオブジェクト
const modals = document.querySelectorAll(".modal");
// カード上のボタン全て
const card_btns = document.querySelectorAll(".card-btn");
// モダル上のクローズボタン全て
const modal_close_btns = document.querySelectorAll(".modal-close");
// forEachで一個一個見てく
card_btns.forEach((btn) => {
btn.addEventListener("click", (e) => {
//引数のeのターゲットidを保存し、値によりスイッチ分岐するようにした
const target = e.target.id;
switch (target) {
case "card-1-btn":
// 元々display=noneにしてある
modals[0].style.display = "block";
break;
case "card-2-btn":
modals[1].style.display = "block";
break;
case "card-3-btn":
modals[2].style.display = "block";
break;
case "card-4-btn":
modals[3].style.display = "block";
break;
case "card-5-btn":
modals[4].style.display = "block";
break;
default:
console.log("nothing applied");
}
});
});
modal_close_btns.forEach((close) => {
close.addEventListener("click", (e) => {
const target = e.target.id;
switch (target) {
case "modal-close-1":
modals[0].style.display = "none";
break;
case "modal-close-2":
modals[1].style.display = "none";
break;
case "modal-close-3":
modals[2].style.display = "none";
break;
case "modal-close-4":
modals[3].style.display = "none";
break;
case "modal-close-5":
modals[4].style.display = "none";
break;
default:
console.log("nothing applied");
}
});
});
// when user clicks on window outside of modal, close
window.onclick = function (e) {
switch (e.target.id) {
case "modal-1":
modals[0].style.display = "none";
case "modal-2":
modals[1].style.display = "none";
case "modal-3":
modals[2].style.display = "none";
case "modal-4":
modals[3].style.display = "none";
case "modal-5":
modals[4].style.display = "none";
default:
console.log("nothing applied");
}
};
改善
それぞれのidを確認してそれによって分岐させることが重複しているような気がしたので、
共通の関数を一つ作り、引数を渡すことで、その中で処理できるようにした。
const modals = document.querySelectorAll(".modal");
const card_btns = document.querySelectorAll(".card-btn");
const modal_close_btns = document.querySelectorAll(".modal-close");
//ここまで一緒
//ボタンそれぞれをforEachで見てイベント関数追加
card_btns.forEach((btn) => {
//関数にターゲットid とbooleanの値を渡す
btn.addEventListener("click", (e) => openCloseModal(e.target.id, false));
});
// モダル上のクローズボタンたちにもイベント関数追加
modal_close_btns.forEach((close) => {
//関数にターゲットid とbooleanの値を渡す
close.addEventListener("click", (e) => openCloseModal(e.target.id, true));
});
// close modal when window is clicked
window.addEventListener("click", (e) => closeModalFromWindow(e.target.id));
//これが上記三つに対する共通の関数
// idとisOpenというbooleanをパラメータに持つ
function openCloseModal(id, isOpen) {
//全ての引数で共通の部分で分岐させる
if (id.includes("1")) {
// booleanで三項演算子
isOpen
? (modals[0].style.display = "none")
: (modals[0].style.display = "block");
} else if (id.includes("2")) {
isOpen
? (modals[1].style.display = "none")
: (modals[1].style.display = "block");
} else if (id.includes("3")) {
isOpen
? (modals[2].style.display = "none")
: (modals[2].style.display = "block");
} else if (id.includes("4")) {
isOpen
? (modals[3].style.display = "none")
: (modals[3].style.display = "block");
} else if (id.includes("5")) {
isOpen
? (modals[4].style.display = "none")
: (modals[4].style.display = "block");
} else {
console.log("no target found.");
}
}
感想
コードがよりまとまって短くなった...気がする。効率良いかつなるべく短くコードを書くを書くことを目標に意識してやっていきたいと思います。