JavaScriptのforEachとdatasetを使って中身がふわっと表示されるタブ切り替えを実装してみる(パターン2)(備忘録)

今回は、jQueryを使用せずに、JavaScriptのforEachメソッドとdatasetプロパティを活用して中身がふわっと表示される、タブ切り替えを実装してみることにした。

前回のページと挙動は同じではあるが、アプローチが異なるので紹介していきたいと思う。cssのソースは前回と全く同じである。

前回のページはこちら

今回のデモは下記に作ったのでご覧いただければと思う。

では実装に入っていきたいと思う。

htmlの記述について

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>タブ切り替え</title>
  <link rel="stylesheet" href="../reset.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main>
    <section>
      <div class="ly_inner" id="menu1">
        <h2>menu1</h2>
        <!-- タブ切り替え -->
        <div class="bl_tabContainer">
          <ul class="bl_tabList">
            <li><a href="" class="active" data-id="tab01">Tab01</a></li>
            <li><a href="" data-id="tab02">Tab02</a></li>
            <li><a href="" data-id="tab03">Tab03</a></li>
          </ul>
          <div class="bl_tabContent">
            <!-- Tab01の内容 -->
            <div class="active" id="tab01">
              <p>Tab01の内容が入りますTab01の内容が入りますTab01の内容が入りますTab01の内容が入りますTab01の内容が入りますTab01の内容が入りますTab01の内容が入りますTab01の内容が入りますTab01の内容が入りますTab01の内容が入ります</p>
            </div>
            <!-- //Tab01の内容 -->
            <!-- Tab02の内容 -->
            <div id="tab02">
              <p>Tab02の内容が入ります</p>
              <p>Tab02の内容が入ります</p>
              <p>Tab02の内容が入ります</p>
              <p>Tab02の内容が入ります</p>
              <p>Tab02の内容が入ります</p>
              <p>Tab02の内容が入ります</p>
              <p>Tab02の内容が入ります</p>
              <p>Tab02の内容が入ります</p>
            </div>
            <!-- //Tab02の内容 -->
            <!-- Tab03の内容 -->
            <div id="tab03">
              <p>Tab03の内容が入ります</p>
            </div>
            <!-- //Tab03の内容 -->
          </div>
        </div>
        <!-- //タブ切り替え -->
        <div class="md_textblock">
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
        </div>
      </div>
    </section>
  </main>
  <script src="style.js"></script>
</body>
</html>

前回のタブ切り替えの時とほぼ一緒であるが、下記の点が変わっている。

<!-- タブ切り替え -->
<div class="bl_tabContainer">
  <ul class="bl_tabList">
    <li><a href="" class="active" data-id="tab01">Tab01</a></li>
    <li><a href="" data-id="tab02">Tab02</a></li>
    <li><a href="" data-id="tab03">Tab03</a></li>
  </ul>
  <div class="bl_tabContent">
    <!-- Tab01の内容 -->
    <div class="active" id="tab01">
      <p>Tab01の内容が入りますTab01の内容が入りますTab01の内容が入りますTab01の内容が入りますTab01の内容が入りますTab01の内容が入りますTab01の内容が入りますTab01の内容が入りますTab01の内容が入りますTab01の内容が入ります</p>
    </div>
    <!-- //Tab01の内容 -->
    <!-- Tab02の内容 -->
    <div id="tab02">
      <p>Tab02の内容が入ります</p>
      <p>Tab02の内容が入ります</p>
      <p>Tab02の内容が入ります</p>
      <p>Tab02の内容が入ります</p>
      <p>Tab02の内容が入ります</p>
      <p>Tab02の内容が入ります</p>
      <p>Tab02の内容が入ります</p>
      <p>Tab02の内容が入ります</p>
    </div>
    <!-- //Tab02の内容 -->
    <!-- Tab03の内容 -->
    <div id="tab03">
      <p>Tab03の内容が入ります</p>
    </div>
    <!-- //Tab03の内容 -->
  </div>
</div>
<!-- //タブ切り替え -->

Tab01〜Tab03のaタグに対して、data-id=”tab01”〜data-id=”tab03”を追加。これは後述するが、JavaScript側で記述するときにhtml側の情報を渡すのに便利なため使用している。ちなみにdata-idの「id」については任意の文字でもOKだ。

また、Tab01〜Tab03の内容に対しても、id=”tab01”〜id=”tab03”を設定している。data-idと同じ名前にしている理由は、javascriptでidを呼び出すときに使いまわしやすくなるためだ。

cssの記述について

@charset "utf-8";

/* ==========================
  初期設定
========================== */
*,
*::before,
*::after {
  box-sizing: border-box;
}
img {
  width: 100%;
}

/* ==========================
  タブ
========================== */

.bl_tabContainer + * {
  margin-top: 30px;
}
/* タブリスト */
.bl_tabList {
  display: flex;
  justify-content: space-between;
}
.bl_tabList li {
  width: 32%;
}
.bl_tabList li a {
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #aaa;
  padding: 20px 10px;
  transition: 0.3s;
}
.bl_tabList li a.active {
  background-color: #fff;
  cursor: text;
}
/* タブコンテンツ */
.bl_tabContent {
  position: relative;
}
.bl_tabContent > div {
  background-color: #fff;
  padding: 20px;
  opacity: 0;
  visibility: hidden;
  transition: 0.3s;
  position: absolute;
  width: 100%;
  top: 0;
  left: 0;
}
.bl_tabContent > div.active {
  opacity: 1;
  visibility: visible;
  position: static;
}
.bl_tabContent > div > * + * {
  margin-top: 10px;
}

/* ==========================
  タブ以外のコンテンツの中身
========================== */
.ly_inner {
  width: 100%;
  max-width: 1080px;
  margin: 100px auto;
  padding: 30px;
  background-color: #ccc;
}
.ly_inner h2 {
  font-size: 150%;
  font-weight: bold;
  margin-bottom: 30px;
}
.md_textblock > * + * {
  margin-top: 10px;
}

/* ====================================
  ここからPC幅
==================================== */
@media screen and (min-width: 768px) {
  .hp_displaySP {
    display: none !important;
  }

  .bl_tabList li a:not(.active):hover {
    background-color: #fff;
  }
}

/* ====================================
  ここからスマホ幅
==================================== */
@media screen and (max-width: 767px) {
  .hp_displayPC {
    display: none !important;
  }
}

こちらは前回の記事と全く同じ内容のため、解説は省略する。詳細は下記ページを参考にしてほしい。

前回の記事はこちら

JavaScriptの記述について

'use strict';

// タブ切り替え
document.addEventListener('DOMContentLoaded', function(){
  const tabList = document.querySelectorAll(".bl_tabList li a");
  const tabContent = document.querySelectorAll(".bl_tabContent > div");

  tabList.forEach(function (clickedTabListA) {
    clickedTabListA.addEventListener('click', function (e) {
      e.preventDefault();

      tabList.forEach(function (clickedTabListB) {
        clickedTabListB.classList.remove('active');
      });
      clickedTabListA.classList.add('active');

      tabContent.forEach(function (contentList) {
        contentList.classList.remove('active');
      });
      document.getElementById(clickedTabListA.dataset.id).classList.add('active');
    })
  });
});

// スムーススクロール
window.addEventListener('DOMContentLoaded', function () {
  const anchorLinks = document.querySelectorAll('a[href^="#"]');
  const anchorLinksArr = Array.prototype.slice.call(anchorLinks);

  anchorLinksArr.forEach(function (link) {
    link.addEventListener('click', function (e) {
      e.preventDefault();
      const targetId = link.hash;
      const targetElement = document.querySelector(targetId);
      const targetOffsetTop = window.pageYOffset + targetElement.getBoundingClientRect().top; //ここに- 50 などと数値を入れるとヘッダー固定のスクロールが実現できる
      window.scrollTo({
        top: targetOffsetTop,
        behavior: "smooth"
      });
    });
  });
});

constで定義している、タブリスト(tabList)とタブの中身(tabContent)の解説は前回同様なので省略する。

forEachメソッドについて

forEachメソッドは、for文と違って幅広い対応はできないが、配列の各要素に対してコールバック関数(functionで記述している処理)による処理を行えるのが特徴。

forEachメソッドは、配列をループする以外には使えないので、今回のタブ切り替えのようにシンプルなものには使いやすいと思う。

内容の解説

tabList.forEach(function (clickedTabListA) {
  clickedTabListA.addEventListener('click', function (e) {
    e.preventDefault();

    tabList.forEach(function (clickedTabListB) {
      clickedTabListB.classList.remove('active');
    });
    clickedTabListA.classList.add('active');

    tabContent.forEach(function (contentList) {
      contentList.classList.remove('active');
    });
    document.getElementById(clickedTabListA.dataset.id).classList.add('active');
  })
});

clickedTabListAは、任意の値でOK。このclickedTabListAに対してクリックした時のイベント発火の処理を記述している。

e.preventDefault();はaリンクをクリックした時にページ遷移しないように設定している。前回の記事と同様だ。

また、clickedTabListBについても、前回のfor文の記事のiとjの関係と同様、clickedTabListAと別の値を指定することで、clickedTabListBの処理が走るようになるので、全てのtabListについているactiveのクラスを取り除くことができる。

このactiveのクラスが取り除かれた上で、クリックしたtabListに対してactiveのクラスを付与する。これでTab01〜Tab03の処理が完了する。

続いて、tabContentに対してもforEachを使って処理をしていく。contentList(任意の値でOK)を指定して、全てのtabContentに対してactiveのクラスを取り除く。

dataset.idについて

最後にhtmlでdata-idとidを記述した部分の解説をしていきたい。

まず、javascriptでdocument.getElementByIdとしているのは、htmlで指定していた「id=”tab01”〜id=”tab03”」を取得するためである。

dataset.idについては、下記のように考えていただく良いかと思う。
・javascriptのdataset.id ⇨htmlのdata-idを呼び出す
※idの文字は任意の値でOK

例えば、ページ上のTab01をクリックしたのであれば、
clickedTabListA.dataset.idの部分は、tab01に置き換わるため、
document.getElementById(tab01)となり、
htmlの「div id=“tab01”」に対してactiveのクラスが付与され、
「div class=“active” id=“tab01”」となるイメージだ。

以上で終わりだが、スムーススクロールの記述は組み合わせて使うことが多いので、前回同様残している。解説は省略したいと思う。

次回もタブ切り替えシリーズの別パターン実装をやっていきたいと思う。

1 返信

トラックバック & ピングバック

  1. […] javascriptのforEachとdatasetを使って中身がふわっと表示されるタブ切り替えを実装してみる(パターン2)(備忘録) […]

コメントはクローズされています。