[自分用メモ]バニラjsのみでタグを切り替えを実装

脱jqをするために、タグ切り替えをvanilla.jsのみで実装しました。
意外と簡単でした。ただまだ、jqの方がコード記述が少ないです。

下記のHTMLをファイルを用意する

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>タブメニュー</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <div class="tab">
        <ul class="tab_menu">
            <li class="tab_menu-item is-active" data-tab="01">menu1</li>
            <li class="tab_menu-item" data-tab="02">menu2</li>
            <li class="tab_menu-item" data-tab="03">menu3</li>
        </ul>
        <ul class="tab_panel">
            <li class="tab_panel-box tab_panel-box001 is-show" data-panel="01"><p class="tab_panel-text">最初のタブです。テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト</p></li>
            <li class="tab_panel-box tab_panel-box002" data-panel="02"><p class="tab_panel-text">2枚目のタブです。テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト</p></li>
            <li class="tab_panel-box tab_panel-box003" data-panel="03"><p class="tab_panel-text">3枚目のタブです。テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト</p></li>
        </ul>
    </div>
    <!--jsファイルを読み込むときは/bodyタグ直前に設置する -->
    <script src="js/main.js"></script>
</body>
</html>

CSSでもいいが今回はSCSSでコンパイルしている

* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
}

ul {
    list-style: none;
}

.tab {
    max-width: 800px;
    margin: 0 auto;
    margin-top: 120px;

    .tab_menu {
        display: flex;
        align-items: flex-end;
        justify-content: center;
        min-height: 50px;

        .tab_menu-item  {
            width: 200px;
            padding: 8px 5px;
            text-align: center;
            margin-right: 6px;
            background-color: #cdcdcd;
            border-top-left-radius: 10px;
            border-top-right-radius: 10px;
            cursor: pointer;
            transition: all .3s;

            &:last-of-type {
                margin-right: 0;
            }
            &.is-active {
                background-color: rgba(48, 172, 249);
                color: #fff;
                padding: 12px 5px;
            }
        }
    }

    .tab_panel {
        width: 100%;

        .tab_panel-box {
            min-height: 400px;
            padding: 10px 30px;
            border-radius: 10px;

            &.tab_panel-box001 {
                background-color: rgb(205, 246, 246);
                display: none;
            }
            &.tab_panel-box002 {
                background-color: rgb(249 227 243);
                display: none;
            }
            &.tab_panel-box003 {
                background-color: rgb(200, 248, 195);
                display: none;
            }

            &.is-show {
                display: block;
            }
        }
    }
}

main.jsに下記を記載する
※詳細はコードの所に記載しています。

    const tabMenus = document.querySelectorAll(".tab_menu-item"); // DOM取得

    tabMenus.forEach((tabmenu) => {
        tabmenu.addEventListener("click", tabSwitch);
    });

    function tabSwitch(e) {
        
        const tabTargetData = e.currentTarget.dataset.tab;  // 要素のデータ属性を取得している。

        // 要素の親要素と、その子要素を取得
        const tabList = e.currentTarget.closest('.tab_menu');
        const tabItems = tabList.querySelectorAll('.tab_menu-item'); 

        // 要素の親要素の兄弟要素の子要素を取得
        const tabPanelItems = tabList.nextElementSibling.querySelectorAll(".tab_panel-box"); 

         // tabの同階層のmenuとpanelのクラスを削除
        tabItems.forEach((tabItem) => {
            tabItem.classList.remove('is-active');
        })
        tabPanelItems.forEach((tabPanelItem) => {
            tabPanelItem.classList.remove("is-show");
        })
        
        // menu要素にis-activeクラスを付加
        e.currentTarget.classList.add("is-active");

        // menuのデータ属性と等しい値を持つパネルにis-showクラスを付加
        tabPanelItems.forEach((tabPanelItem) => {
            if (tabPanelItem.dataset.panel ===  tabTargetData) {
              tabPanelItem.classList.add('is-show');
            }
          })
    }

この記事が気に入ったらサポートをしてみませんか?