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!

avaScriptを使用して 複数階層のタブメニューのコンテンツ表示

解決したいこと

洗濯したボタンに該当するコンテント(内容)を表示させたい。

例)
Ruby on Railsでサロン予約ができるWebアプリをつくっています。
記事を投稿する機能の実装中に狙っている表示ができずかなり時間が経過しております。
解決方法を教えて下さい。

発生している問題

https://gyazo.com/27d110281873abf33a73ca8178de638d

上記動画のように、第2階層のメニューをクリックした際に、コンソール内に記述してあるPタグの内容を実際のビューでも
表示させ、それぞれのメニューにある出しわけを行いたい。

該当するソースコード

<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" unko-id="10">スケジュール確認</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段目めにゅ -->


<!-- .メニュー内容 -->
<div class="tab-content">
  <div class="tab-content__item js-tab-target " unko-menu="1" >
    <p class="tab-content__item" >スケジュール確認のコンテンツが入ります。。スケジュール確認のコンテンツが入ります。。スケジュール確認のコンテンツが入ります。。スケジュール確認のコンテンツが入ります。。スケジュール確認のコンテンツが入ります。。</p>
  </div><!-- .tab-content__item -->
  <div class="tab-content__item js-tab-target" id="tab02">
    <p>定休日選択のコンテンツが入ります。定休日選択のコンテンツが入ります。定休日選択のコンテンツが入ります。定休日選択のコンテンツが入ります。定休日選択のコンテンツが入ります。定休日選択のコンテンツが入ります。</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 -->
<%# /Footer前 %>
</div>

例)

.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;

}

/* タブコンテンツ */
.tab-content {
  border: 1px solid #ccc;

}
.tab-content__item {
  box-sizing: border-box;
  padding: 20px;
  display: none;
  text-align: left;
}

.tab-content__item:active {
  display:flex;
}
(()=>{

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

    menuDetail[i].addEventListener('click', (e) => {
      const init = () => {
        menuMoreDetail[i].style.display = 'block';
        console.log(menuMoreDetail)
      };
      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');

      //クリックされた時に is-active を追加/削除
      for (const tabMenuDetail of tabMenuDetails) {
        console.log(tabMenuDetail)
        if (tabMenuDetail.id === currentMenu.dataset.id) {
         tabMenuDetail.classList.add('is-active');
        } else {
         tabMenuDetail.classList.remove('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');
      // }


      //ここから
      const menuDetailSub = tabMenu.querySelectorAll("[unko-id]")
      const menuMoreDetailSub = tabMenu.querySelectorAll("[unko-menu]")
      const tabMenuDetailsSub = tabMenu.querySelectorAll(".tab-content__item");

      for(let i = 0; i < menuDetailSub.length; i++) {
      menuDetailSub[i].addEventListener('click', (e) =>{
        const taketakeshi = () =>{
          menuMoreDetail[i].style.display = 'block';
          console.log(menuDetailSub)
        };
        taketakeshi();

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

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

      //クリックされた時に is-active を追加/削除
      for (const tabMenuDetailSub of tabMenuDetailsSub) {
        console.log(tabMenuDetailSub)
        if (tabMenuDetailSub.id === currentMenuSub.dataset.id) {
         tabMenuDetailSub.classList.add('is-active');
        } else {
         tabMenuDetailSub.classList.remove('is-active');
        }
      }
      })}


       //ここまで
    })
  }

自分で試したこと

GIFでも確認できる通りですが、console.logで確認しながら作業を行なっており、
第2階層のメニューをクリックした時に表示させたいPタグの中身までは引っ張って来れている状態です。
あとは表示の問題でCSSのdisplayをnoneにするかしないかだと思い、思いつくパターンを試して見ましたが、
全くうまくいきませんでした。
0

1Answer

あちこちで不整合があるように思います。

まず、html の id は、html全体でユニークにする(同じ値のものは1つだけ、2つ上存在しない)必要があります。
具体的には id="tab02"id="tab03" が複数あるのは問題です。

また、css での :active はリンクやボタンが押されている間の疑似クラスです。
そのため .tab-content__item:active はおそらく間違った定義になっています。 .tab-content__item.is-active だと思います。

(最後のあたり)
  .tab-content__item {
    box-sizing: border-box;
    padding: 20px;
    display: none;
    text-align: left;
  }

- .tab-content__item:active {
+ .tab-content__item.is-active {
    display:flex;
  }

また、1段目のメニューのクリック時の処理のなかで、2段階目のサブメニューのクリック時の処理を実施していますが、毎回全部のサブメニューの処理をしているのは無駄だと思います。ループの外に出してよいと思います。

また tab-content__item のクラスが、div タグと p タグの両方に入っているところがあります。おそらく div タグだけにつけるのが正しいと思います。

とりあえず、以下のようにしたらどうでしょうか?

まずは、htmlで大きく変えたのは、2つ。

1つ目は、tab-content__item の要素の id を id="contentNN" の形式にしました。
これは tabNN 形式だと、ユニークにならないためです。

2つ目は second-menu クラスの要素(サブメニュー)の data-menu に contentNN という形式の値を入れました。これは tab-content__item の要素と紐づけるために同じ値を入れています。

    <div id="js-tab">
        <ul class="tab-menu">
            <li class="tab-menu__item"><span class="tab-trigger js-tab-trigger" data-id="tab01">予約管理</span>
                <ul class="tab-menu-detail" id="tab01">
                    <li class="second-menu js-tab-target " data-menu="content01">スケジュール確認</li>
                    <li class="second-menu js-tab-target " data-menu="content02">定休日選択</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 " data-menu="content03">新規メニュー作成</li>
                    <li class="second-menu js-tab-target " data-menu="content04">既存メニュー編集・削除</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="content05">新規クーポン作成</li>
                    <li class="second-menu js-tab-target " data-menu="content06">既存クーポン編集・削除</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="content07">現在のレビュー</li>
                    <li class="second-menu js-tab-target " data-menu="content08">コメント返信</li>
                </ul>
            </li>
        </ul>
        <!-- .tab-menu -->

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


        <!-- .メニュー内容 -->
        <div class="tab-content">
            <div class="tab-content__item js-tab-target " id="content01">
                <p>
                    スケジュール確認のコンテンツが入ります。。スケジュール確認のコンテンツが入ります。。スケジュール確認のコンテンツが入ります。。スケジュール確認のコンテンツが入ります。。スケジュール確認のコンテンツが入ります。。
                </p>
            </div><!-- .tab-content__item -->
            <div class="tab-content__item js-tab-target" id="content02">
                <p>定休日選択のコンテンツが入ります。定休日選択のコンテンツが入ります。定休日選択のコンテンツが入ります。定休日選択のコンテンツが入ります。定休日選択のコンテンツが入ります。定休日選択のコンテンツが入ります。
                </p>
            </div><!-- .tab-content__item -->
            <div class="tab-content__item js-tab-target" id="content03">
                <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="content04">
                <p>タブ4のコンテンツが入ります。タブ4のコンテンツが入ります。タブ4のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。タブ3のコンテンツが入ります。
                </p>
            </div><!-- .tab-content__item -->
        </div><!-- .tab-content -->
    </div>

次に javascript ですが、サブメニューのクリック時の処理をループの外に出して、不要な処理(と思われるもの)を削除しました。
また、クリックしたサブメニューの data-menu の値と同じ id を持つコンテンツをアクティブにしています。

        window.addEventListener('load', () => {
            const tabMenu = document.getElementById("js-tab")

            const menuDetail = tabMenu.querySelectorAll("[data-id]")
            const tabMenuDetails = tabMenu.querySelectorAll(".tab-menu-detail");
            for (let i = 0; i < menuDetail.length; i++) {
                //タブメニュークリック時

                menuDetail[i].addEventListener('click', (e) => {

                    //クリックされた要素(メニュー要素)を取得
                    const currentMenu = e.currentTarget;

                    //ターゲットとなる要素(タブメニューdata属性ちと等しいid値を持つコンテンツ要素を取得
                    const 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');

                    //クリックされた時に is-active を追加/削除
                    for (const tabMenuDetail of tabMenuDetails) {
                        console.log(tabMenuDetail)
                        if (tabMenuDetail.id === currentMenu.dataset.id) {
                            tabMenuDetail.classList.add('is-active');
                        } else {
                            tabMenuDetail.classList.remove('is-active');
                        }
                    }
                });
            }

            //ここから
            const menuDetailSub = tabMenu.querySelectorAll("[data-menu]")
            const tabMenuDetailsSub = tabMenu.querySelectorAll(".tab-content__item");

            for (let i = 0; i < menuDetailSub.length; i++) {
                menuDetailSub[i].addEventListener('click', (e) => {

                    //クリックされた要素(メニュー要素)を取得
                    const currentMenuSub = e.currentTarget;

                    //クリックされた時に is-active を追加/削除
                    for (const tabMenuDetailSub of tabMenuDetailsSub) {
                        console.log(tabMenuDetailSub)
                        if (tabMenuDetailSub.id === currentMenuSub.dataset.menu) {
                            tabMenuDetailSub.classList.add('is-active');
                        } else {
                            tabMenuDetailSub.classList.remove('is-active');
                        }
                    }
                })
            }
            //ここまで
        });

0Like

Your answer might help someone💌