👻

【初心者】JavaScriptでアコーディオンメニューを作る

2024/03/23に公開

はじめに

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行ずつ説明していきます!

  1. document.addEventListener('DOMContentLoaded', function() {

    • これは、ウェブページが完全に読み込まれたときに、次の中括弧 {} の間にあるコードを実行する指示です。
  2. const accordions = document.querySelectorAll('.accordion');

    • この行では、.accordion というクラス名を持つ要素をすべて探して、accordions という変数に保存します。
    • アコーディオンメニューを作るための箱ですね。
  3. let activeAccordion = null;

    • activeAccordion という変数を作って、最初は null(何もない状態)に設定。
    • これは、今開いているアコーディオンを記録するための変数。
  4. accordions.forEach(function(accordion) {

    • forEachでaccordions の中にある一つ一つのアコーディオンに対して処理していきます。
  5. const accordionMenu = accordion.querySelector('.accordion-menu');

    • accordion の中から .accordion-menu というクラス名を持つ要素を探して、accordionMenu という変数に保存。
    • これはアコーディオンのタイトルの部分です。
  6. accordionMenu.addEventListener('click', function() {

    • accordionMenu がクリックされたときに処理を行います。(次が重要!)
  7. if (activeAccordion && activeAccordion !== accordion) {

    • もし activeAccordion(今開いているアコーディオン)が存在していて、それが今クリックしたアコーディオンと違う場合、次の処理
    • (これは、新しいアコーディオンを開く前に、前に開いていたアコーディオンを閉じるためのものです)
  8. activeAccordion.classList.remove('active');

    • 前に開いていたアコーディオン(activeAccordion)から 'active' というクラス名を取り除きます。
    • (これにより、前に開いていたアコーディオンが閉じられます)
  9. accordion.classList.toggle('active');

    • 今クリックしたアコーディオン(accordion)に 'active' というクラス名を付けたり外したりします。
    • これにより、クリックしたアコーディオンの開閉を制御します。
  10. activeAccordion = accordion.classList.contains('active') ? accordion : null;

    • 今クリックしたアコーディオン(accordion)が開いている('active' というクラス名を持っている)場合は、activeAccordion にそのアコーディオンを設定。
    • そうでない場合は、activeAccordionnull(何もない状態)に設定。

これで、タイトルをクリックすると、そのアコーディオンが開き、前に開いていたアコーディオンは閉じられるアコーディオンメニューの完成です!

最初はもっとヘンテコなコードだったのですがClaude3にリファクタリングしてもらいながらこの形になりました!(AI様様ですw)

ではまた!

Discussion