Vue.jsで頑張るハンバーガーメニュー

#はじめに#
**「ハンバーガーメニューは古臭い」**

最近、僕はその言葉を聞く機会が増えた。
それでも、僕はハンバーガーメニューが好きだ。

確かに、ハンバーガーメニューにはメニュー項目を探しにくいという欠点がある。
しかし、コンテンツを表示するエリアを広く使える、つまり表示エリアをほぼ占領しないというメリットがあるので時と場合によってはまだまだ現役で使えると僕は思っている。

ということで、Vue.jsを使ってハンバーガーメニューを実装してみる('ω')

とりあえず、完成形はこんな感じになる。

![Humberger-Google-Chrome-2020-05-23-19-10-24.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508580/0ca6a55a-f351-0c42-5422-184a5af86a0b.gif)

サンプルサイトはこちらから
https://helloworld753315.github.io/vue_hamburger/

GitHubのリポジトリはこちらから
https://github.com/helloworld753315/vue_hamburger

では、実際に手を動かしてみよう！！

#参考ページ

- 公式ドキュメント
https://jp.vuejs.org/v2/guide/

- 基礎から学ぶVue.js
    - 書籍　
    www.amazon.co.jp/dp/4863542453
    - サイト（動作デモ）
    https://cr-vue.mio3io.com/

- HTMLクイックリファレンス
https://developer.mozilla.org/ja/docs/Web/CSS/transform-function/translateX
http://www.htmq.com/css3/transform_rotate.shtml







#必要な知識（使う知識）
- HTML,CSS
- Vue.js
    - classの操作
    - イベントハンドリング
    - トランジション


#書く前に

まずは、classをバインドする方法の復習を少し...

```vuejs:class_bind.html
<div id="app">
    <h1 v-bind:class="{'color':color_bind}">色を変える</h1>
</div>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    var app = new Vue({
      el: '#app',
      data: {
        color_bind:true
      }
    })
  </script>
```
```css:style.css
.color{
  color: blue;
}
```

Vue.jsでclassを操作したい場合、`v-bind:class`を使うことでそれが可能になる。

例えば、上記のコードでは`color`というclass名を`color_bind`というプロパティと結び付けている。
なので、`color_bind`がtrueなら`color`クラスが付与され、falseなら付与されない。つまり、`color_bind`がtrueなら文字色が青になりfalseなら黒色のまま！

###1.trueの場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508580/bd410c93-001c-2505-674d-7d8d2f3c5523.png)
###2.falseの場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508580/8b8b7219-f199-dd7e-e071-3bf7f60e1a0f.png)

#実際に書いてみる

だらだらと説明しても面白くないので、とりあえず完成形。

```vuejs:index.html
<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Hamberger</title>
  <link rel="stylesheet" href="style.css">
</head>

<body>
  <div id="app">
    <!--ハンバーガーメニューのボタン-->
    <div class="hamburger_btn" v-on:click='ActiveBtn=!ActiveBtn'>
      <span class="line line_01" v-bind:class="{'btn_line01':ActiveBtn}"></span>
      <span class="line line_02" v-bind:class="{'btn_line02':ActiveBtn}"></span>
      <span class="line line_03" v-bind:class="{'btn_line03':ActiveBtn}"></span>
    </div>
    <!--サイドバー-->
    <transition name="menu">
      <div class="menu" v-show="ActiveBtn">
          <ul>
              <li><a href="#">項目1</a></li>
              <li><a href="#">項目2</a></li>
              <li><a href="#">項目3</a></li>
              <li><a href="#">項目4</a></li>
              <li><a href="#">項目5</a></li>
          </ul>
      </div>
  </transition>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    var app = new Vue({
      el: '#app',
      data: {
        ActiveBtn: false
      }
    })
  </script>
</body>

</html>
```

```css:style.css
/*ボタン*/
.hamburger_btn {
  position: fixed; /*常に最上部に表示したいので固定*/
  top: 0;
  right: 0;
  width: 70px;
  height: 72px;
  cursor: pointer;
  z-index: 50;
}

.hamburger_btn .line {
  position: absolute;
  top: 0;
  left: 20px;
  width: 32px;
  height: 2px;
  background: #333333;
  text-align: center;
}

.hamburger_btn .line_01 {
  top: 16px;
  transition: 0.4s ease;
}
.hamburger_btn .line_02 {
  top: 26px;
  transition: 0.4s ease;
}
.hamburger_btn .line_03 {
  top: 36px;
  transition: 0.4s ease;
}


.btn_line01 {
  transform: translateY(10px) rotate(-45deg);
  transition: 0.4s ease;
}
.btn_line02 {
  transition: 0.4s ease;
  opacity: 0;
}
.btn_line03 {
  transform: translateY(-10px) rotate(45deg);
  transition: 0.4s ease;
}

/*サイドバー*/
.menu-enter-active, .menu-leave-active {
  transition: opacity 0.4s;
}
.menu-enter, .menu-leave-to {
  opacity: 0;
}
.menu-leave, .menu-enter-to{
  opacity: 1;
}

.menu li {
  list-style: none;
  line-height: 1;
  padding: 1rem;
}
.menu {
  background-color: rgba(197, 197, 197, 0.671);
  z-index: 30;
  padding: 2rem 1rem;
  position: fixed;
  width: 20rem;
  height: 80rem;
  top: 0;
  right: 0;
}
.menu a {
  color: rgb(66, 66, 66);
  text-decoration: none;
  font-size: 1.2rem;
  padding: 0 2rem;
}
.menu ul{
  margin: 1rem;
  padding: 0;
}

```

##必要な機能

Vueを使ってハンバーガーメニューを作るには、次の２つの機能が必要

- ボタン
    - ボタンを押したときにボタンが×に変わる
    - もう一度押したときに元に戻る
- サイドバー
    - ボタンが押されたらメニューを表示する
    - もう一度ボタンが押されたらメニューを閉じる
    - 表示切替のときのアニメーション

##手順

###共通部分
`v-on:click`を使うと、イベントの制御ができるので「ボタンがクリックされたら`ActiveBtn`の真偽値を逆にする（反転する）」という処理を書く。

```vuejs:
v-on:click='ActiveBtn=!ActiveBtn'
```


###ボタン
最初にやった`v-bind:class`を使って`ActiveBtn`がtrueだったら`btn_line01`,
`btn_line02`,`btn_line03`のそれぞれのクラス属性を付与するようにする。
ざっくり表にするとこんな感じ。

|ActiveBtn|class属性|
|---|---|---|
|true|付与する|
|false|付与しない|

あとは、cssで開閉時のアニメーションを書いていくだけ。

cssの方を簡単に説明すると、classが付与されたら`translate`と`rotate`でline_01とline_03の位置と角度を変更して、line_02の透明度を0にしているシンプルなものだ。

###サイドバー
`v-show`ディレクティブを使ってサイドバーの表示切替の部分を作ろう!
共通部分として作った`ActiveBtn`のデータを`v-show="ActiveBtn"`と書いて紐づける。
そうすることで、ボタンを押したときに表示を切り替えることが可能になる。

最後に、サイドバーの表示切替時のアニメーションを作ろう!

表示切替のアニメーションにはVue.jsのトランジションという機能を使う。
わからない方のためにざっくり説明すると、cssトランジション・アニメーションを簡単に使えるようにした機能だ。
使う際は、`<transion>`タグで囲んで使う。名前を付けられるので今回は`menu`としておく。

`<transion>`タグで囲んだ場所には、トランジションクラスを使ってアニメーションを適用できる。
対象をDOMに追加するとき（表示するとき）のアニメーションはenter~、DOMから削除されるとき（非表示にするとき）はleave~を使う。

言葉で説明してもわかりにくいので、簡単な図を使って見ていこう(;・∀・)

![transiton_enter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508580/e70f2f79-2bb0-be28-c4e5-52547054780c.png)

![transiton_leave.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508580/9046fc7b-2636-c53e-eb0e-fb71ef5506af.png)

図を見ると、サイドバーを表示するときは、`.menu-enter`で透明度0から始めて`.menu-enter-to`で透明度が1へと変化しているのが分かる。
また、サイドバーを非表示にするときは、`.menu-leave`で透明度1から始めて、`.menu-leave-to`で透明度1に変化している。

書いたコードはこんな感じだ。

```css

.menu-enter-active, .menu-leave-active {
  transition: opacity 0.4s;
}
.menu-enter, .menu-leave-to {
  opacity: 0;
}
.menu-leave, .menu-enter-to{
  opacity: 1;
}
```

補足しておくと、`enter-active`と`leave-active`のところは透明度を0.4秒で変化させるという意味だ。

こんな感じの手順でコードを書いていけば、ハンバーガーメニューの完成(*'▽')


#最後に

長々と書いてしまいましたが、以上です
普段はTwitterでいろいろ呟いたりしてるので何か聞きたいこと、指摘などあればどんどん送ってほしいです!
https://mobile.twitter.com/helloworld193