【使いまわし可】jQueryを使わずVanilla JSでタブメニュー/タブコンテンツを実装する方法
Web2022年4月10日
jQueryを使用するとググってコピペするだけで意外と容易に実装できるタブメニュー/タブコンテンツですが、今更ですが素のJavaScript(Vanilla JS)で基本的な機能を調べながら組んでみましたのでそのソースコードの紹介と解説をしてみようと思います。
サンプルコード
html
<div class="mod-list-tab-01-wrapper">
<ul class="mod-list-tab-01">
<li><a href="#" data-id="js-tab-01" class="is-active">タブメニュー1</a></li>
<li><a href="#" data-id="js-tab-02">タブメニュー2</a></li>
<li><a href="#" data-id="js-tab-03">タブメニュー3</a></li>
<li><a href="#" data-id="js-tab-04">タブメニュー4</a></li>
<li><a href="#" data-id="js-tab-05">タブメニュー5</a></li>
<li><a href="#" data-id="js-tab-06">タブメニュー6</a></li>
</ul>
</div>
<div class="js-tab-content is-active" id="js-tab-01">
<p>タブメニュー1の中身が入ります</p>
</div>
<div class="js-tab-content" id="js-tab-02">
<p>タブメニュー2の中身が入ります</p>
</div>
<div class="js-tab-content" id="js-tab-03">
<p>タブメニュー3の中身が入ります</p>
</div>
<div class="js-tab-content" id="js-tab-04">
<p>タブメニュー4の中身が入ります</p>
</div>
<div class="js-tab-content" id="js-tab-05">
<p>タブメニュー5の中身が入ります</p>
</div>
<div class="js-tab-content" id="js-tab-06">
<p>タブメニュー6の中身が入ります</p>
</div>
css
div.mod-list-tab-01-wrapper ul.mod-list-tab-01{
width: 100%;
margin: 0 0 20px 0;
display: flex;
flex-wrap: wrap;
}
div.mod-list-tab-01-wrapper ul.mod-list-tab-01 li{
width: calc((100% - 10px) / 3);
margin: 0 5px 5px 0;
box-sizing: border-box;
}
div.mod-list-tab-01-wrapper ul.mod-list-tab-01 li a{
display: block;
padding: 10px 5px;
background: #efefef;
text-align: center;
font-size: 14px;
}
div.mod-list-tab-01-wrapper ul.mod-list-tab-01 li a.is-active{
background: #f7f3e7;
color: #333;
font-weight: bold;
}
div.mod-list-tab-01-wrapper ul.mod-list-tab-01 li:nth-child(3n+3){
margin-right: 0;
}
.js-tab-content{
display: none;
background: #ff0000;
color: #fff;
padding: 50px;
text-align: center;
}
.js-tab-content.is-active{
display: block;
}
JavaScript
//変数宣言
const menuItems = document.querySelectorAll('.mod-list-tab-01 > li > a');
const contents = document.querySelectorAll('.js-tab-content');
//タブメニュークリック時
menuItems.forEach(clickeditem =>{
clickeditem.addEventListener('click',e =>{
//デフォルト動作キャンセル
e.preventDefault();
//タブメニューのclass付け替え
menuItems.forEach(item =>{
item.classList.remove('is-active');
});
clickeditem.classList.add('is-active');
//コンテンツのclass付け替え
contents.forEach(content =>{
content.classList.remove('is-active');
});
document.getElementById(clickeditem.dataset.id).classList.add('is-active');
});
});
解説
まずはhtmlについてですが、タブメニューの要素とコンテンツを用意します。タブメニューのスタイルはサイトに応じてカスタマイズください。ポイントとしては、data-id属性の値と、各タブコンテンツを内包するid名をイコールにしておくことです、後ほどJavaScriptについての解説で詳しく触れますが、クリックされた要素のdata-idの値を同じidを持つタブコンテンツをアクティブ化(display:block;)するためにこの命名は必須ルールとなります。
また、メニューのアクティブ時の見た目のスタイルを.activeで用意しておくとともに、初期表示するアイテムのメニューとタブコンテンツにはそれぞれ.activeを付与しておきます。
cssについては、あらかじめ全タブコンテンツに「.js-tab-content」を付与し、このclassでdisplay:none;により非表示にしておきます。あわせて表示する際のclassである.is-activeを用意しておき、表示/非表示の切り替えにおいてはこの.is-activeが付け外しされるという挙動になります。
JavaScriptについてですが、まずは変数「menuItems」「contents」にそれぞれquerySelectorAllでタブメニューの各a要素、タブコンテンツの各要素を格納しています。次にmenuItemsに対しforEachを回してメニュークリック時にイベントリスナーを呼び出すのですが、まずは「e.preventDefault();」でデフォルトの挙動をキャンセルします、これをしないとhref="#"によるアンカーリンクが発動してしまうので。
次に、タブメニューのclass付け替えを行います。変数menuItemsに対してforEachでいったんすべてのa要素から.is-activeをremoveし、クリックしたa要素に改めて.is-activeを付与してスタイルチェンジを実行します。
最後に、各タブコンテンツのclass制御を実行します。menuItemsと同じように今度はすべてのcontentsに対して.is-activeをremoveし、「clickeditem.dataset.id」でクリックしたa要素が保持していたdata-id属性と同じ値のclassを持っているタブコンテンツに対し.is-activeを付与します。これでタブコンテンツが切り替わります。
デモ
実際に動作を確認できるデモページも公開しておりますのであわせてご確認ください。
まとめ
素のJavaScriptでタブメニュー/コンテンツを実装してみたのは初めてだったのですが、やってみると意外とjQuery使用時と変わらないコード量で実現することができました。今後もこういったちょっとした機能はライブラリに頼らず実装していければと思います。いずれはこのサイトのjs機能もすべて素のJavaScriptに置き換えたい。JavaScriptでタブメニュー/コンテンツを実装の際は、ぜひ本記事をご参考にしていただければ幸いです。