Vue.jsを使ってドロワーメニューを作ってみた

こんにちは。

Vue.jsやReactが流行っていることもあり、つい最近Vue.jsについて学び始めました。（まだ触れてみたくらい？）

Vue.jsに触れてみて何かに活用してみたいなと思ったので、ドロワーメニューに活用したものを学習ログとしてここに残そうと思います。

# ドロワーメニューの完成版

簡易ではありますが、Vue.jsを使って下記gifのようなドロワーメニューを作ってみました。

![ドロワーメニュー.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2868165/c07c4895-e8cc-04d0-553e-8ba692aca7ab.gif)

Vue.jsを使って書いた完成版のコードは下記になります。


```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>ドロワーメニュー</title>
  <link rel="stylesheet" href="style.css">
  <script src="https://unpkg.com/vue@next"></script>
  <script src="app.js" defer></script>
  <script src="script.js" defer></script>
</head>
<body>
  <div id="app">
    <nav class="header__nav" :class="{'is-drawerActive' : isActive}">
      <h2 class="visuallyHidden">サイト内メニュー</h2>
      <button type="button" class="hamburger" aria-controls="globalNav" :aria-expanded="isActive" @click="drawer">Menu</button>
      <ul id="globalNav" class="globalNav">
        <li v-for="i in 5">メニュー{{ i }}</li>
      </ul>
    </nav>
  </div>
</body>
</html>
```

```css:style.css
* {
  margin: 0;
  padding: 0;
}

body {
  padding: 5rem;
  background-color: #fff;
}

.visuallyHidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  border: 0;
  white-space: nowrap;
  clip-path: inset(50%);
}

.globalNav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  padding: 5rem;
  background-color: #212121;
  color: #fff;
  transition: transform .3s ease-in-out;
  transform: translate3d(100%, 0 , 0);
}

.is-drawerActive .globalNav {
  transform: translate3d(0, 0 , 0);
}

.hamburger {
  position: fixed;
  top: 3rem;
  right: 3rem;
  z-index: 2;
  width: 5rem;
  height: 5rem;
  border-radius: 50%;
  background-color: transparent;
  border: 1px solid currentColor;
  mix-blend-mode: exclusion;
  color: #fff;
  cursor: pointer;
  appearance: none;
}

```


```javaScript:app.js
Vue.createApp({
  data() {
    return {
      isActive: false,
    };
  },
  methods: {
    drawer() {
      this.isActive = !this.isActive;
    }
  }
}).mount("#app");
```

# Vue.jsを使ったドロワーメニューの作り方

Vue.jsを使ったドロワーメニューの作り方について下記に記載していきます。

## 基本的なHTML

Vueを使用するためにはインストールをする必要がありますが、今回はCDNを利用しているため、headタグ内に下記コードを記載します。

```html:index.html
<head>
  <script src="https://unpkg.com/vue@next"></script>
</head>
```

CDNを読み込んだ後は、基本的なHTMLとJSファイル内にVueのインスタンスを作成していきます。
今回はVueで操作していきたい要素に「app」というid名に付けています。

```html:index.html
<body>
    <div id="app">
      <nav class="header__nav">
        <h2 class="visuallyHidden">サイト内メニュー</h2>
        <button type="button" class="hamburger" aria-controls="globalNav" aria-expanded="false">Menu</button>
        <ul id="globalNav" class="globalNav">
          <li>メニュー1</li>
          <li>メニュー2</li>
          <li>メニュー3</li>
          <li>メニュー4</li>
          <li>メニュー5</li>
        </ul>
      </nav>
    </div>
</body>
```

```javascript:app.js
Vue.createApp({
  data() {
    return {
        
    };
  },
}).mount("#app");
```

## Vueのディレクティブを使ってメニューを書き換える

基本的なHTMLを書いた後は、Vueの「v-for」ディレクティブを使って繰り返し処理をしていきます。
下記の書き方をすることによって、メニュー1〜メニュー5までを画面上に映し出すことができます。

```html:index.html
 <li v-for="i in 5">メニュー{{ i }}</li>
```

「v-for」を用いてメニューを書き換えたHTMLが下記になります。

```html:index.html
<body>
    <div id="app">
      <nav class="header__nav">
        <h2 class="visuallyHidden">サイト内メニュー</h2>
        <button type="button" class="hamburger" aria-controls="globalNav" aria-expanded="false">Menu</button>
        <ul id="globalNav" class="globalNav">
          <li v-for="i in 5">メニュー{{ i }}</li>
        </ul>
      </nav>
    </div>
</body>

```


## メソッドを使ってドロワーメニュを表示/非表示にする

「is-drawerActive」クラスが付与されるとメニューが出てくる仕様なため、「v-on」と「v-bind」ディレクティブ、さらにメソッドを使ってclassの付け外しが出来るようにしていきます。

buttonタグをクリックしたときに「is-drawerActive」クラスの付け外しが出来るようにしたいため、buttonタグに「v-on」ディレクティブを、navタグに「v-bind」ディレクティブを付け加えます。

```html:index.html
    <div id="app">
      <nav class="header__nav" :class="{'is-drawerActive' : isActive}">
        <h2 class="visuallyHidden">サイト内メニュー</h2>
        <button type="button" class="hamburger" aria-controls="globalNav" :aria-expanded="isActive" @click="drawer">
          Menu
        </button>
        <ul id="globalNav" class="globalNav">
          <li v-for="i in 5">メニュー{{ i }}</li>
        </ul>
      </nav>
    </div>
```

また、JSファイルにメソッドを定義していきます。

```javascript:app.js
Vue.createApp({
  data() {
    return {
      isActive: false,
    };
  },
  methods: {
    drawer() {
      this.isActive = !this.isActive;
    }
  }
}).mount("#app");

```

dataプロパティ内にてisActiveの値をfalseに定義しておき、drawerメソッドでfalseとtrueが切り替わるようにしています。

そのため、属性を操る「v-bind」を用いることで、「isActive」がtrueの時に「is-drawerActive」クラスが付与され、falseの時には「is-drawerActive」クラスが外されます。

ちなみにですが、「v-on」と「v-bind」は省略記法を用いています。
```html:HTML
「v-on」：イベントを指定する
<button v-on:click="drawer">Menu</button>
<!-- 省略記法 -->
<button @click="drawer">Menu</button>


「v-bind」：属性を操作する
<nav class="header__nav" v-bind:class="{'is-drawerActive' : isActive}">
<!-- 省略記法 -->
<nav class="header__nav" :class="{'is-drawerActive' : isActive}">
```

# 終わりに

Vue.jsを使えば、JavaScriptよりも少ない記述量でドロワーメニューを動かせることがわかりました。
もっと応用できるようにVue.jsを学びたいと思うと同時に、JavaScriptの理解も深めていきたいと思います。