ryo386700
@ryo386700 (RYO YAMANE)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

JavaScriptを使用して 複数階層のタブメニュー切替を行いたいです

前提・実現したいこと

JavaScriptを使用して、複数階層(第3階層まで)のタグメニュー実装を行いたいです。

発生している問題

下記、Gifのように第1階層の選択時の色は、選択エリアごとに変わるものの、
選択したことによって出現した第2階層のメニューは、選択エリアごとに消えない。
https://gyazo.com/383699c4017be9011999dd60554c615d

第1階層選択時の色のように、第2階層のメニューも選択外のところは消したい。

何卒よろしくお願いいたします。

該当のソースコード

(()=>{

window.addEventListener('load', () => {
  const tabMenu = document.getElementById("js-tab")
  const menuDetail = tabMenu.querySelectorAll("[data-id]")
  const menuMoreDetail = tabMenu.querySelectorAll("[data-menu]")
  console.log(menuMoreDetail)
  for(let i = 0; i < menuDetail.length; i++) {
    //タブメニュークリック時

    menuDetail[i].addEventListener('click', (e) => {
      const init = () => {
        menuMoreDetail[i].style.display = 'block';
      };
      init();

      //クリックされた要素(メニュー要素)を取得
      let currentMenu = e.currentTarget;
      //ターゲットとなる要素(タブメニューdata属性ちと等しいid値を持つコンテンツ要素を取得
      let currentContent = document.getElementById(currentMenu.dataset.id);
      console.log(currentContent)

      // すべてのタブメニューの'is-active'クラスを削除
      for(let i = 0; i < menuDetail.length; i++) {
        menuDetail[i].classList.remove('is-active');
      }
      // クリックしたタブメニューに'is-active'クラスを追加
      currentMenu.classList.add('is-active');

       // タブコンテンツを非アクティブにする
       for(let i = 0; i < menuMoreDetail.length; i++) {
         menuMoreDetail[i].classList.remove('is-active');
       }
       // 対象コンテンツ(指定したIDの要素があったら)を表示させる
       if(currentContent !== null) {
         currentContent.classList.add('is-active');
       } else {
         currentContent.classList.remove('is-active');
       }

    })
  }    
})
})();
/* タブメニュー */
.tab-menu {
  display: flex;
  margin: 0 -5px;
}

.tab-menu__item {
  box-sizing: border-box;
  width: -webkit-fill-available;
}


.tab-trigger { /* label */
  text-align: left;
  cursor: pointer;
  display: block;
  padding: 10px;
  border: 1px solid #ccc;
  border-bottom: 0;
  border-radius: 5px 5px 0 0;
  overflow: hidden;
  background-color: lightgray;
  position: relative;
}

.tab-trigger.is-active {
  background-color: darkgoldenrod;

}

/* 2段目たぶ */
.tab-menu-detail{
  display: none;
}

.tab-menu-detail.is-active {
  display: flex;
}

.second-menu {
    width: 100%;
    text-align: left;
    cursor: pointer;
    padding: 6px;
    border: 2px solid dimgray;
    border-radius: 5px 5px 0 0;
    overflow: hidden;
    background-color: lightslategrey;
    position: relative;

}
<div id="js-tab">
<ul class="tab-menu" >
  <li class="tab-menu__item"><span class="tab-trigger js-tab-trigger is-active" data-id="tab01">予約管理</span>
    <ul class="tab-menu-detail" id="tab01">
        <li class="second-menu js-tab-target " data-menu="1">スケジュール確認</li>
        <li class="second-menu js-tab-target " data-menu="2">定休日選択</li>
    </ul>
  </li>

  <li class="tab-menu__item"><span class="tab-trigger js-tab-trigger" data-id="tab02">メニュー作成</span>
    <ul class="tab-menu-detail" id="tab02">
        <li class="second-menu js-tab-target is-active" data-menu="3">新規メニュー作成</li>
        <li class="second-menu js-tab-target " data-menu="4">既存メニュー編集・削除</li>
    </ul>
  </li>

  <li class="tab-menu__item"><span class="tab-trigger js-tab-trigger" data-id="tab03">クーポン作成</span>
    <ul class="tab-menu-detail" id="tab03">
        <li class="second-menu js-tab-target " data-menu="5">新規クーポン作成</li>
        <li class="second-menu js-tab-target " data-menu="6">既存クーポン編集・削除</li>
    </ul>
  </li>

  <li class="tab-menu__item"><span class="tab-trigger js-tab-trigger" data-id="tab04">レビュー確認</span>
    <ul class="tab-menu-detail" id="tab04">
        <li class="second-menu js-tab-target " data-menu="7">新規メニュー作成</li>
        <li class="second-menu js-tab-target " data-menu="8">既存メニュー編集・削除</li>
    </ul>
  </li>
</ul>
<!-- .tab-menu -->

<!-- .2段目めにゅ -->


<!-- .2段目めにゅ -->
<div class="tab-content">
  <div class="tab-content__item js-tab-target is-active" id="tab01">
    <p>タブ1のコンテンツが入ります。タブ1のコンテンツが入ります。タブ1のコンテンツが入ります。タブ1のコンテンツが入ります。タブ1のコンテンツが入ります。タブ1のコンテンツが入ります。タブ1のコンテンツが入ります。タブ1のコンテンツが入ります。タブ1のコンテンツが入ります。タブ1のコンテンツが入ります。タブ1のコンテンツが入ります。タブ1のコンテンツが入ります。</p>
  </div><!-- .tab-content__item -->
  <div class="tab-content__item js-tab-target" id="tab02">
    <p>タブ2のコンテンツが入ります。タブ2のコンテンツが入ります。タブ2のコンテンツが入ります。タブ2のコンテンツが入ります。タブ2のコンテンツが入ります。タブ2のコンテンツが入ります。タブ2のコンテンツが入ります。タブ2のコンテンツが入ります。タブ2のコンテンツが入ります。タブ2のコンテンツが入ります。タブ2のコンテンツが入ります。タブ2のコンテンツが入ります。</p>
  </div><!-- .tab-content__item -->
  <div class="tab-content__item js-tab-target" id="tab03">
    <p>タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。</p>
  </div><!-- .tab-content__item -->
  <div class="tab-content__item js-tab-target" id="tab04">
    <p>タブ4のコンテンツが入ります。タブ4のコンテンツが入ります。タブ4のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。</p>
  </div><!-- .tab-content__item -->
</div><!-- .tab-content -->
</div>

試したこと

jsファイルにif文でelse以下を追加し、removeする記述を追加してみたが、特に変化なし。

// 対象コンテンツ(指定したIDの要素があったら)を表示させる
if(currentContent !== null) {
currentContent.classList.add('is-active');
} else {
currentContent.classList.remove('is-active');
}

参考にしたページ

https://blog.pranktone.net/web/javascript/20200304150200.html

0

2Answer

対策としては、選択されていない tab-menu-detail クラスを持つ要素から is-active クラスを削除すればよいと思います。

例えば、事前に以下のように tab-menu-detail クラスの一覧を作っておいて (変数名は適当です)

  const tabMenuDetails = tabMenu.querySelectorAll(".tab-menu-detail");

クリックされた時に is-active を追加/削除すればよいのではないでしょうか。

       for (const tabMenuDetail of tabMenuDetails) {
         if (tabMenuDetail.id === currentMenu.dataset.id) {
          tabMenuDetail.classList.add('is-active');
         } else {
          tabMenuDetail.classList.remove('is-active');
         }
       }

その際 currentContent 関連の処理はすべて削除しておいてください。

1Like

Comments

  1. @ryo386700

    Questioner

    お忙しいところコメントありがとうございます!
    いただきましたアドバイスで挙動確認できました!
    ```
    https://gyazo.com/fe468d92b30dc2cbd8a2015682c4b47a
    ```
    今回のご指摘の内容でfor of文に関して質問させてください。
    初めて目にするのですいません、、、
    ```
    https://www.sejuku.net/blog/20228
    ```
    上記URLで大方の説明は確認ました。
    今回のfor (const tabMenuDetail of tabMenuDetails)の記述では、
    tabMenuDetailにtabMenuDetailsの中身(配列)を追加して、
    クリックしたtabMenuDetailのidとcurrentMenu.dataset.idが一緒なら
    is-activeを付与する、それ以外は削除する?
    という認識であってますでしょうか?
    理解がまだあまり追いついてなくてすいません。
    ご回答いただけますと幸いでございます。

コメント(返信)だとコードブロックが使えないみたいなので、分けて書きます。

for は何種類か書き方があります。

以下の for の書き方は

for (const tabMenuDetail of tabMenuDetails) {
    // ...
}

以下の書き方とほぼ同じです(index 用の変数 i が無いだけです。tabMenuDetails が配列以外の場合には少し違いますが、今回は配列なので)。

for (let i = 0; i < tabMenuDetails.length; i++) {
    const tabMenuDetail = tabMenuDetails[i];
    // ...
}

index を使う必要がない場合には(構文を知っていれば)こちらの方がわかりやすい、また変数がないので(定数だけなので)、最近は for...of が良くつかわれると思います。

つまり

       for (const tabMenuDetail of tabMenuDetails) {
         if (tabMenuDetail.id === currentMenu.dataset.id) {
          tabMenuDetail.classList.add('is-active');
         } else {
          tabMenuDetail.classList.remove('is-active');
         }
       }

は、以下の内容と同じです。

       for (let i = 0; i < tabMenuDetails.length; i++) {
         if (tabMenuDetails[i].id === currentMenu.dataset.id) {
          tabMenuDetails[i].classList.add('is-active');
         } else {
          tabMenuDetails[i].classList.remove('is-active');
         }
       }

言葉で表現するなら tabMenuDetails 配列の中身を順番に tabMenuDetail に取り出してきて、tabMenuDetailid が、クリックされた要素 currentMenudataset.id と同じなら tabMenuDetailis-active クラスを付与する、それ以外は削除する、といった感じです。

1Like

Comments

  1. @ryo386700

    Questioner

    返信遅くなり大変申し訳ございません。
    詳細な回答ありがとうございます。
    javascriptに関しまして、まだ知識が甘く点でしか理解ができていない状態でしたので、非常に助かりました!
    わざわざご回答いただいていたのに、ご返信遅くなり申し訳ございません。
    引き続き何卒よろしくお願いいたします。

Your answer might help someone💌