[JS]Tab Menuについて

# はじめに
こちらも順序整理の為に記していきます。

# 実装

まずは形を作っていきます。

```html:index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Tab Menu</title>
  <link rel="stylesheet" href="css/styles.css">
</head>
<body>
  <div class="container">
    <ul class="menu">
      <li><a href="#" class="active">サイトの概要</a></li>
      <li><a href="#">サービス内容</a></li>
      <li><a href="#">お問い合わせ</a></li>
    </ul>

    <section class="content active">
      サイトの概要。サイトの概要。サイトの概要。サイトの概要。
      サイトの概要。サイトの概要。サイトの概要。サイトの概要。
    </section>

    <section class="content">
      サービス内容。サービス内容。サービス内容。サービス内容。
      サービス内容。サービス内容。サービス内容。サービス内容。
    </section>
    <section class="content">
      お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。
      お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。
    </section>
  </div>

  
  <script src="js/main.js"></script>
</body>
</html>

```

```css:css/styles.css
body {
  font-size: 14px;
}

.container {
  margin: 30px auto;
  width: 500px;
}

.menu {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
}

.menu li a {
  display: inline-block;
  width: 100px;
  text-align: center;
  padding: 8px 0;
  color: #333;
  text-decoration: none;
  border-radius: 4px 4x 0 0;
}

/* 上のメニューのタイトルの部分 */
.menu li a.active {
  background: #333;
  color: #fff;
}

/* 上のメニューのタイトルの部分のactiveクラスがついてない部分の動き */
/* hoverされるとactiveクラスがついてない部分は「opacity」によって薄くなる */
.menu li a:not(.active):hover {
  opacity: 0.5;
  transition: opacity 0.4s;
} 

/* menuの内容部分のactiveクラスがついている部分の見た目の部分 */
.content.active {
  background: #333;
  color: #fff;
  min-height: 150px;
  padding: 12px;
  display: block;
}

/* menuの内容部分のactiveクラスがついていない部分はdisplayで最初は見えなくしておく */
.content {
  display: none;
}

```
このような感じに見た目がなります。
![スクリーンショット 2021-03-22 16.51.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/892628/347ab931-9107-5373-9163-c1d19b4bbd00.png)


## JSを実装していく

その前に、「data」属性を使ってmenuのタイトル部分と内容の部分を紐づけていきます

```html:index.html
<div class="container">
    <ul class="menu">

<!-- こちらには「data-id」をつける -->
      <li><a href="#" class="active" data-id="about">サイトの概要</a></li>
      <li><a href="#" data-id="service">サービス内容</a></li>
      <li><a href="#" data-id="contact">お問い合わせ</a></li>
    </ul>

<!-- こちらには「id」:紐付けたい「data-id」と同じ名前をつける -->
    <section class="content active" id="about">
      サイトの概要。サイトの概要。サイトの概要。サイトの概要。
      サイトの概要。サイトの概要。サイトの概要。サイトの概要。
    </section>

    <section class="content" id="service">
      サービス内容。サービス内容。サービス内容。サービス内容。
      サービス内容。サービス内容。サービス内容。サービス内容。
    </section>
    <section class="content" id="contact">
      お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。
      お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。
    </section>
  </div>


```

最初に付けていたactiveクラスを外して表示したいmenuタイトルとmenuの内容部分に付けていくという実装をしていきます。
しかし！別々ではなくタイトル部分と内容部分を紐付けする必要があります。


```javascript:js/main.js
'use strict';

{
  const menuItems = document.querySelectorAll('.menu li a');
  const contents = document.querySelectorAll('.content');

/* ページ遷移するのをキャンセルしてeventオブジェクトを渡す：デフォルトの動作をキャンセル */
  menuItems.forEach(clickedItem => {
    clickedItem.addEventListener('click', e => {
      e.preventDefault();

/* menuタイトル部分：「forEach」でactiveクラスを外した後にclickしたmenuタイトルにactiveクラスをつける */
      menuItems.forEach(item => {
        item.classList.remove('active');
      });
      clickedItem.classList.add('active');

/* menu内容部分：こちらでもactiveクラスを外して、その後にidを
取得しactiveクラスをつける */
      contents.forEach(content => {
        content.classList.remove('active');
      });
      document.getElementById(clickedItem.dataset.id).classList.add('active');
    });
  });
}

```

# 完成！！

完成したものをまとめるとこのような感じになります。

```html:index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Tab Menu</title>
  <link rel="stylesheet" href="css/styles.css">
</head>
<body>
  <div class="container">
    <ul class="menu">
      <li><a href="#" class="active" data-id="about">サイトの概要</a></li>
      <li><a href="#" data-id="service">サービス内容</a></li>
      <li><a href="#" data-id="contact">お問い合わせ</a></li>
    </ul>

    <section class="content active" id="about">
      サイトの概要。サイトの概要。サイトの概要。サイトの概要。
      サイトの概要。サイトの概要。サイトの概要。サイトの概要。
    </section>

    <section class="content" id="service">
      サービス内容。サービス内容。サービス内容。サービス内容。
      サービス内容。サービス内容。サービス内容。サービス内容。
    </section>
    <section class="content" id="contact">
      お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。
      お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。
    </section>
  </div>

  
  <script src="js/main.js"></script>
</body>
</html>

```

```css:css/styles.css
body {
  font-size: 14px;
}

.container {
  margin: 30px auto;
  width: 500px;
}

.menu {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
}

.menu li a {
  display: inline-block;
  width: 100px;
  text-align: center;
  padding: 8px 0;
  color: #333;
  text-decoration: none;
  border-radius: 4px 4x 0 0;
}

.menu li a.active {
  background: #333;
  color: #fff;
}

.menu li a:not(.active):hover {
  opacity: 0.5;
  transition: opacity 0.4s;
} 

.content.active {
  background: #333;
  color: #fff;
  min-height: 150px;
  padding: 12px;
  display: block;
}

.content {
  display: none;
}

```

```javascript:js/main.js
'use strict';

{
  const menuItems = document.querySelectorAll('.menu li a');
  const contents = document.querySelectorAll('.content');

  menuItems.forEach(clickedItem => {
    clickedItem.addEventListener('click', e => {
      e.preventDefault();

      menuItems.forEach(item => {
        item.classList.remove('active');
      });
      clickedItem.classList.add('active');

      contents.forEach(content => {
        content.classList.remove('active');
      });
      document.getElementById(clickedItem.dataset.id).classList.add('active');
    });
  });
}

```

こちらもつけ外しで実装できました！！

[![Image from Gyazo](https://i.gyazo.com/1f4fb79c475303140b23e0dd2ef854fb.gif)](https://gyazo.com/1f4fb79c475303140b23e0dd2ef854fb)

# 最後に

こちらもアニメーションを変えたり、色を変えたりするともう少し違った感じにできますね！！
内容も最初は隠したい場合は「opacity」が「display」を使用して隠したりの実装もしていく感じかな。
今日はここまでです。

お疲れ様でした！！

# 参考


https://developer.mozilla.org/ja/docs/Web/API/Event/preventDefault

データ属性についてです↓

https://into-the-program.com/dataset/

https://developer.mozilla.org/ja/docs/Learn/HTML/Howto/Use_data_attributes