ネイティブのJavaScript(脱jQuery)でアコーディオンメニューを実装するサンプル
javascript

ネイティブのJavaScript(脱jQuery)でアコーディオンメニューを実装するサンプル

アバター by pranktone
サンプルコード

ネイティブのJavaScript(脱jQuery)、アロー関数も使ってアコーディオンメニューを実装するサンプルを作ってみました。jQuery本体の重さを許容できるのであれば、jQueryを使った方がかなりシンプルに書けると思いますが、jQueryは使いたくない時の参考にしていただければと思います。

別記事のCSSとhtmlのcheckboxを使って高さ可変のアコーディオンメニューを実装するサンプルと、jQueryのtoggleSlideを使ってアコーディオンメニューを実装するサンプルとの比較も兼ねて作ったので、htmlは似た構成にしています。

html

<span class="accordion-trigger js-accordion-trigger is-opened">アコーディオン1</span>
<ul class="accordion-target list js-accordion-target">
  <li class="list__item"><a href="#">メニュー1</a></li>
  <li class="list__item"><a href="#">メニュー2</a></li>
  <li class="list__item"><a href="#">メニュー3</a></li>
  <li class="list__item"><a href="#">メニュー4</a></li>
  <li class="list__item"><a href="#">メニュー5</a></li>
</ul><!-- .accordion-target -->

<span class="accordion-trigger js-accordion-trigger">アコーディオン2</span>
<ul class="accordion-target list js-accordion-target">
  <li class="list__item"><a href="#">メニュー1メニュー1メニュー1メニュー1メニュー1メニュー1メニュー1メニュー1メニュー1メニュー1メニュー1メニュー1メニュー1メニュー1メニュー1メニュー1メニュー1メニュー1</a></li>
  <li class="list__item"><a href="#">長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気長いテキストも平気</a></li>
  <li class="list__item"><a href="#">メニュー3</a></li>
  <li class="list__item"><a href="#">メニュー4</a></li>
  <li class="list__item"><a href="#">メニュー5</a></li>
</ul><!-- .accordion-target -->

jQueryのtoggleSlideを使ってアコーディオンメニューを実装するサンプルと同様のhtmlです、アコーディオンを展開させる要素(トリガーになる要素)は'.accordion-trigger'、アコーディオンの本体(展開する要素)は'.accordion-target'です。

それぞれ、JavaScriptを使用して動かすので、JavaScriptでの操作のために 'js-' というプレフィックスをつけた'.js-accordion-trigger', '.js-accordion-target'というクラスをそれぞれにつけています。

CSS

.accordion-trigger { /* label */
  text-align: left;
  cursor: pointer;
  display: block;
  padding: 15px;
  padding-right: 42px; /* padding + icon width */
  border-bottom: 1px solid #ccc;
  background-color: lightblue;
  position: relative;
}

/* icon */
.accordion-trigger::before,
.accordion-trigger::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  right: 15px;
  margin: auto;
  height: 2px;
  width: 12px;
  background-color: #000;
  transition: all .1s ease-out;
}

.accordion-trigger::after {
  transform: rotate(90deg);
}

.accordion-trigger.is-opened::after {
  opacity: 0;
  transform: rotate(0);
}
/* /icon */


.accordion-target { /* target */
  box-sizing: border-box;
  overflow: hidden;
  height: 0;
  transition: height .4s ease-out;
  text-align: left;
}

.accordion-target.list > .list__item { /* target-child */
  box-sizing: border-box;
  border-bottom: 1px solid #ccc;
  opacity: 1;
  padding-top: 15px;
  padding-bottom: 15px;
}

.accordion-target.list > .list__item > a {
  display: block;
  margin-top: -15px;
  margin-bottom: -15px;
  padding: 15px;
  color: #000;
  text-decoration: none;
}

基本的にはjQueryのtoggleSlideを使ってアコーディオンメニューを実装するサンプルと同様の内容です。トリガー要素にcursor: pointerを付与。アイコンは擬似要素::before, ::afterを使って構成しています。

違うところ(変更点)として、展開する要素('.accordion-target')に展開のアニメーションのためにtransitionを追加しています。javascript側で指定した方がいいかもしれませんが、今回はCSSで指定しています。

JavaScript

document.addEventListener('DOMContentLoaded', () => {
    // トリガークラス'.js-accordion-trigger'を持つ要素を取得
    const accordionTrigger = document.querySelectorAll('.js-accordion-trigger');

    for (let i = 0; i < accordionTrigger.length; i++) {

        // '.is-opened'がついていて展開している要素に高さを付加
        if(accordionTrigger[i].classList.contains('is-opened')) {
            // scrollHeightプロパティはpaddingを含む表示されていない要素の高さを取得
            accordionTrigger[i].nextElementSibling.style.height = accordionTrigger[i].nextElementSibling.scrollHeight + 'px';
        }

        // トリガーを押した時のアクション
        accordionTrigger[i].addEventListener('click', (e) => {

            // クリックされた要素(トリガー要素)を取得
            let currentElement = e.currentTarget;

            // 同じ親要素を持つ隣接した次の要素'.js-accordion-target'(展開対象の要素)を取得
            let accordionTarget = currentElement.nextElementSibling;

            if (accordionTarget.style.height) {

                //トリガーの'is-opened'クラスを削除
                currentElement.classList.remove('is-opened');
                //
                accordionTarget.style.height = null;

            } else {
                //トリガーの'is-opened'クラスを追加
                currentElement.classList.add('is-opened');

                // scrollHeightプロパティはpaddingを含む表示されていない要素の高さを取得
                accordionTarget.style.height = accordionTarget.scrollHeight + 'px';
            }
        });
    }
});
デモ GitHub

アコーディオン実装に関する記事

コメント

まだ、コメントはありません。

トラックバックURL

https://blog.pranktone.net/web/javascript/20191030171503.html/trackback
ありきたりな日常と
それとない非日常を
紡ぐ記録
SKIP