【初心者】JavaScriptでアコーディオンメニューを作る
はじめに
Netflixのwebサイトの模写をしていて、Q&Aの箇所でアコーディングメニューを実装する場面がありました。
そこで詰まったのが、タイトルをクリックすると、そのアコーディオンが開き、前に開いていたアコーディオンは閉じられる仕様にすることでした。
最初はclass名を都度変えてcssでアニメーションさせればいいかと考えていたんですが、、
アコーディオンメニューの数がちょっと多い、、
そんなわけで奮闘した記録を残しておきます。
CSSでのアニメーション
さっき述べたCSSでのアニメーションです。
.accordion-section {
width: 80vw;
height: auto;
margin: 0 auto;
}
.accordion {
margin-top: 2rem;
width: 80%;
height: auto;
background: #434242;
font-size: 1.5rem;
}
.accordion-menu {
padding: 1rem;
}
.accordion-text {
height: 0;
background: #434242;
border-top: solid 1px #000;
line-height: 2.5rem;
overflow: auto;
}
.accordion-1.active .accordion-text {
animation: open1 0.5s ease forwards;
}
.accordion-2.active .accordion-text {
animation: open2 0.5s ease forwards;
}
/* 他のアコーディオンのアニメーション */
@keyframes open1 {
100% {
width: 100%;
padding: 1rem;
height: auto;
}
}
@keyframes open2 {
100% {
width: 100%;
padding: 1rem;
height: auto;
}
}
ここではaccordionにactive要素が付いたらテキストが出てくるアニメーションを書いています。
しかし、これでは一つ一つのアコーディオンメニューにクラスをつけてアニメーションさせなければいけないのでめちゃくちゃ非効率、、
「JavaScriptでもっと効率よく書けないかなぁ」と試行錯誤した結果がこちら
JavaScriptで実装
document.addEventListener('DOMContentLoaded', function() {
const accordions = document.querySelectorAll('.accordion');
let activeAccordion = null;
accordions.forEach(function(accordion) {
const accordionMenu = accordion.querySelector('.accordion-menu');
accordionMenu.addEventListener('click', function() {
if (activeAccordion && activeAccordion !== accordion) {
activeAccordion.classList.remove('active');
}
accordion.classList.toggle('active');
activeAccordion = accordion.classList.contains('active') ? accordion : null;
});
});
});
このコードの流れを1行ずつ説明していきます!
-
document.addEventListener('DOMContentLoaded', function() {
- これは、ウェブページが完全に読み込まれたときに、次の中括弧
{
と}
の間にあるコードを実行する指示です。
- これは、ウェブページが完全に読み込まれたときに、次の中括弧
-
const accordions = document.querySelectorAll('.accordion');
- この行では、
.accordion
というクラス名を持つ要素をすべて探して、accordions
という変数に保存します。 - アコーディオンメニューを作るための箱ですね。
- この行では、
-
let activeAccordion = null;
-
activeAccordion
という変数を作って、最初はnull
(何もない状態)に設定。 - これは、今開いているアコーディオンを記録するための変数。
-
-
accordions.forEach(function(accordion) {
- forEachで
accordions
の中にある一つ一つのアコーディオンに対して処理していきます。
- forEachで
-
const accordionMenu = accordion.querySelector('.accordion-menu');
- 各
accordion
の中から.accordion-menu
というクラス名を持つ要素を探して、accordionMenu
という変数に保存。 - これはアコーディオンのタイトルの部分です。
- 各
-
accordionMenu.addEventListener('click', function() {
-
accordionMenu
がクリックされたときに処理を行います。(次が重要!)
-
-
if (activeAccordion && activeAccordion !== accordion) {
- もし
activeAccordion
(今開いているアコーディオン)が存在していて、それが今クリックしたアコーディオンと違う場合、次の処理 - (これは、新しいアコーディオンを開く前に、前に開いていたアコーディオンを閉じるためのものです)
- もし
-
activeAccordion.classList.remove('active');
- 前に開いていたアコーディオン(
activeAccordion
)から'active'
というクラス名を取り除きます。 - (これにより、前に開いていたアコーディオンが閉じられます)
- 前に開いていたアコーディオン(
-
accordion.classList.toggle('active');
- 今クリックしたアコーディオン(
accordion
)に'active'
というクラス名を付けたり外したりします。 - これにより、クリックしたアコーディオンの開閉を制御します。
- 今クリックしたアコーディオン(
-
activeAccordion = accordion.classList.contains('active') ? accordion : null;
- 今クリックしたアコーディオン(
accordion
)が開いている('active'
というクラス名を持っている)場合は、activeAccordion
にそのアコーディオンを設定。 - そうでない場合は、
activeAccordion
をnull
(何もない状態)に設定。
- 今クリックしたアコーディオン(
これで、タイトルをクリックすると、そのアコーディオンが開き、前に開いていたアコーディオンは閉じられるアコーディオンメニューの完成です!
最初はもっとヘンテコなコードだったのですがClaude3にリファクタリングしてもらいながらこの形になりました!(AI様様ですw)
ではまた!
Discussion