Vuetify と Vue Router でレスポンシブなナビゲーションを作ってみました

# はじめに

最初に作ったものを載せておきます。

### デモ

https://upbeat-nobel-068b4d.netlify.com/

![vuetify.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29699/1a46db25-6f82-5873-f280-04cc6a31958e.gif)

### コード

https://github.com/youbeer/vuetify-vuerouter-navbar-example

### 事前準備

VueCLI3 のインストールを行なってください

# 【Vue】プロジェクトの作成

```bash:terminal
$ vue create vuetify-vuerouter-navbar-example
```

いくつか質問が表示されるので

- Manually select features を選択肢し
- Router を追加してください

その他はお好みでどうぞ

```bash:terminal
Vue CLI v3.7.0
┌───────────────────────────┐
│  Update available: 3.8.2  │
└───────────────────────────┘
? Please pick a preset:
  default (babel, eslint)
❯ Manually select features
```

```bash:terminal
? Please pick a preset: Manually select features
? Check the features needed for your project:
 ◉ Babel
 ◯ TypeScript
 ◯ Progressive Web App (PWA) Support
❯◉ Router
 ◯ Vuex
 ◯ CSS Pre-processors
 ◉ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing
```

# Vuetify を追加

プロジェクト直下に移動し Vuetify をインストールします。

```bash:terminal
$ cd vuetify-vuerouter-navbar-example
$ vue add vuetify
```

preset は Default (recommended)を選択してください

```bash:terminal
? Choose a preset:
❯ Default (recommended)
  Prototype (rapid development)
  Configure (advanced)
```

サーバを起動

```bash:terminal
$ yarn serve
```

http://localhost:8080/ をブラウザで開いて
**Welcome to Vuetify** の文字が出てくれば OK です

![Screen Shot 2019-05-29 at 10.34.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29699/f56bd9c6-0070-4062-3d1a-73764c5907b7.png)

# プロジェクトを確認

plugins ディレクトリに vuetify.js が作られていて
それを main.js でインポートしているようです。

```javascript:src/plugins/vuetify.js
import Vue from "vue";
import Vuetify from "vuetify/lib";
import "vuetify/src/stylus/app.styl";

Vue.use(Vuetify, {
  iconfont: "md"
});
```

```javascript:src/main.js
import Vue from "vue";
import "./plugins/vuetify";

// ... 略
```

# コンポーネントの作成

ここからいよいよ本題です。
Header.vue を作成しナビゲーションの内容を記述します。

```vue:src/components/Header.vue
<template>
  <div>
    <v-navigation-drawer v-model="drawer" absolute temporary>
      <v-list class="pa-1">
        <v-list-tile avatar>
          <v-list-tile-avatar>
            <img src="https://randomuser.me/api/portraits/men/85.jpg" />
          </v-list-tile-avatar>
          <v-list-tile-content>
            <v-list-tile-title>John Leider</v-list-tile-title>
          </v-list-tile-content>
        </v-list-tile>
      </v-list>
      <v-list>
        <v-text-field
          clearable
          flat
          label="Search"
          prepend-inner-icon="search"
          solo
          single-line
          hide-details
        ></v-text-field>
      </v-list>
      <v-list class="pt-0" dense>
        <v-divider></v-divider>
        <v-list-tile v-for="item in items" :key="item.title" :to="item.to">
          <v-list-tile-action>
            <v-icon>{{ item.icon }}</v-icon>
          </v-list-tile-action>
          <v-list-tile-content>
            <v-list-tile-title>{{ item.title }}</v-list-tile-title>
          </v-list-tile-content>
        </v-list-tile>
      </v-list>
    </v-navigation-drawer>
    <v-toolbar dark color="primary" clipped-left fixed app>
      <v-toolbar-side-icon
        @click.stop="drawer = !drawer"
        class="hidden-md-and-up"
      ></v-toolbar-side-icon>
      <v-toolbar-title class="headline text-uppercase white--text">
        <span>Vuetify</span>
        <span class="font-weight-light">MATERIAL DESIGN</span>
      </v-toolbar-title>
      <v-spacer></v-spacer>
      <v-expand-x-transition>
        <v-text-field
          class="hidden-sm-and-down"
          clearable
          flat
          label="Search"
          prepend-inner-icon="search"
          solo-inverted
          single-line
          hide-details
          v-show="showSearchInput"
        ></v-text-field>
      </v-expand-x-transition>
      <v-toolbar-items class="hidden-sm-and-down">
        <v-btn icon @click="showSearchInput = !showSearchInput">
          <v-icon>search</v-icon>
        </v-btn>
        <v-btn flat to="/">Home</v-btn>
        <v-btn flat to="/about">About</v-btn>
      </v-toolbar-items>
    </v-toolbar>
  </div>
</template>

<script>
export default {
  name: "Header",
  data() {
    return {
      drawer: null,
      showSearchInput: false,
      items: [
        { title: "Home", icon: "dashboard", to: "/" },
        { title: "About", icon: "question_answer", to: "/about" }
      ]
    };
  }
};
</script>
```

### ナビゲーションとサイドパネル

下記を参考にしました。

- [Navigation drawer — Vuetify\.js](https://vuetifyjs.com/en/components/navigation-drawers#navigation-drawer)
- [Toolbars — Vuetify\.js](https://vuetifyjs.com/en/components/toolbars#toolbar)

### アニメーション

`<v-expand-x-transition>`で検索 box の表示切替のときにアニメーションを付けています。

- [Transitions — Vuetify\.js](https://vuetifyjs.com/ja/framework/transitions)

```vue:v-expand-x-transition
<v-expand-x-transition>
  <v-text-field
    class="hidden-sm-and-down"
    clearable
    flat
    label="Search"
    prepend-inner-icon="search"
    solo-inverted
    single-line
    hide-details
    v-show="showSearchInput"
  ></v-text-field>
</v-expand-x-transition>
```

### ブレークポイント

`hidden-md-and-up`　と
`hidden-sm-and-down`
で画面サイズによって表示切替をするブレークポイントをつけています。

- [Display helpers — Vuetify\.js](https://vuetifyjs.com/ja/framework/display)

```vue:hidden-md-and-up
<v-toolbar-side-icon
  @click.stop="drawer = !drawer"
  class="hidden-md-and-up"
></v-toolbar-side-icon>
```

```vue:hidden-sm-and-down
<v-toolbar-items class="hidden-sm-and-down">
  <v-btn icon @click="showSearchInput = !showSearchInput">
    <v-icon>search</v-icon>
  </v-btn>
  <v-btn flat to="/">Home</v-btn>
  <v-btn flat to="/about">About</v-btn>
</v-toolbar-items>
```

### App.js で Header.vue を呼び出す

```vue:src/App.vue
<template>
  <v-app>
    <Header />
    <v-content>
      <v-container fluid fill-height>
        <v-layout justify-center align-center>
          <router-view></router-view>
        </v-layout>
      </v-container>
    </v-content>
  </v-app>
</template>

<script>
import Header from "@/components/Header";
export default {
  name: "App",
  components: {
    Header
  }
};
</script>
```

さて、完成したので再度 http://localhost:8080/ へアクセスして確認してみましょう
こんな表示になっていれば OK です。
![Screen Shot 2019-05-29 at 12.30.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29699/269c3dc8-10e1-8c79-740c-c8fe61c1a7d2.png)

# おわりに

最後まで読んでいただきありがとうございました。
Vuetify は Theme も公開されているようですね
中には無料の物もあるようなので試してみてはいかがでしょうか
[Free / Premium Themes — Vuetify\.js](https://vuetifyjs.com/ja/themes/premium)

Vue.js は至れり尽くせりですね 😁