QR忘れ物アプリ (3) メニュー [Vue,Vuetify,Firebase]

# はじめに
構成
1. 環境構築: https://qiita.com/rayan/items/5d04ee2ca7860c220dec
2. ログインページ: https://qiita.com/rayan/items/1f0576395b9727635461
3. メニュー: __今回__

GitHubリポジトリ
> 準備中

# 操作するファイル
- src
    - components
        - __Drawer.js__
        - __Header.js__
    - router
        - __index.js__
    - views
        - __MainMenu.vue__

## src/components/Drawer.vue
ナビゲーションメニュー。いくつかのビューで共通する要素のため、componentsの中に入っている。

- Drawer.vue内では`show`というpropを定義しています。これはDrawer要素の表示の有無を示している。
- ナビゲーションメニュー表示後、閉じた場合には`show=false`になる。この変化を親コンポーネントであるHeaderの`show`に適用するために以下の処理を行う。
    - `show`の変化(`true->false, false->true`)を`watch`で検出。
    - `this.$emit('update:show', this.show)`を行う。
        - これは(`true->false, false->true`)の両方で発火するため、`this.$emit('update:show', false)`にするとDrawerが開かなくなる。
    - 親であるHeaderに`:show.sync="show"`がある。これは以下の二つの役割を担っている。
        - `:show="show"`ではpropである`show`(左)に`show`(右)の値を代入
        - `v-on:update:show="show = $event"`では子の`update:show`イベントを受けて親の`show`(右)の値を更新

```vuejs
<template>
  <v-navigation-drawer
    v-model="show"
    absolute
    temporary
  >
    <v-list>
      <v-list-item-group
        v-model="selectedItem"
        color="primary"
      >
        <v-list-item
          v-for="(item, i) in items"
          :key="i"
          :to="item.link"
        >
          <v-list-item-icon>
            <v-icon v-text="item.icon"></v-icon>
          </v-list-item-icon>
            <v-list-item-content>
          <v-list-item-title v-text="item.text"></v-list-item-title>
          </v-list-item-content>
        </v-list-item>
      </v-list-item-group>
    </v-list>
  </v-navigation-drawer>
</template>

<script>
export default {
  name: "Drawer",
  components: {
    //
  },
  props: {
    show: {
      type: Boolean,
      default: false
    }
  },
  data: () => ({
    selectedItem: 1,
    items: [
      { text: 'Preferences', icon: 'mdi-account-cog', link: '/userPreferences'},
      { text: 'Item Registeration', icon: 'mdi-tag-plus' , link: '/itemRegisteration'},
      { text: 'Item List', icon: 'mdi-tag-multiple', link: '/itemList'},
    ]
  }),
  watch: {
    show() {
      this.$emit('update:show', this.show);
    }
  },
};
</script>
```

## src/components/Header.vue
ヘッダー要素。いくつかのビューで共通する要素のため、componentsの中に入っている。

- `v-app-bar-nav-icon`をクリックすることによって、propsを用いてインポートしたDrawerを表示している。
    - 表示していない状態(`show=false`)から表示する状態(`show=true`)に変化させる。
- Header.vue内では`title`というpropを定義している。これはHeader要素で表示する文字列を示している。

```vuejs
<template>
  <div>
    <v-card
      class="mx-auto"
      tile
    >
      <v-toolbar>
        <v-app-bar-nav-icon @click.stop="show = !show"></v-app-bar-nav-icon>
        <v-toolbar-title>{{title}}</v-toolbar-title>
      </v-toolbar>
    </v-card>
    <Drawer :show="show" v-on:update:show="show = $event"/>
  </div>
</template>

<script>
import Drawer from '@/components/Drawer'

export default {
  name: "Header",
  components: {
    Drawer
  },
  data: () => ({
    show: false
  }),
  props: {
    title: String,
  },
};
</script>
```

## src/views/MainMenu.vue
メインメニューの要素。

- props
    - `<Header :title="title"/>`によってHeaderのpropである`title`(左)の値を`title`(右)の値に設定する。

```vuejs
<template>
  <div>
    <Header :title="title"/>
  </div>
</template>

<script>
import Header from '@/components/Header'

export default {
  name: "MainMenu",
  components: {
    Header
  },
  data: () => ({
    title: 'Main Menu'
  }),
};
</script>
```

## router/index.js
新しくつくったMainMenuページの情報を追加する。

```javascript
import Vue from "vue";
import VueRouter from "vue-router";

Vue.use(VueRouter);

const routes = [
  {
    path: "*",
    redirect: "/"
  },
  {
    path: "/mainMenu",
    name: "MainMenu",
    meta: { requiresAuth: true },
    component: () =>
      import("@/views/MainMenu.vue"),
  },
  {
    path: "/",
    name: "Authentication",
    component: () =>
      import("@/views/Authentication.vue"),
  },
];

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});

router.beforeEach((to, from, next) => {
  let requiresAuth = to.matched.some(record => record.meta.requiresAuth)
  let currentUser = firebase.auth().currentUser
  if (requiresAuth) { // if this page requires auth, redirect to auth page
    if (!currentUser) {
      next({
        path: '/',
        query: { redirect: to.fullPath }
      })
    } else {
      next()
    }
  } else {
    next() // this is required
  }
})

export default router;
```

# Build
- ビルドし、動作をテストする。動作のテストにはFirebase Emulatorが必要であるため、起動する。

```bash
npm run build
firebase emulators:start
```

- `dist/index.html`をブラウザで閲覧する。ログイン後、移動するMainMenuページに移動する。
    - ![mainmenu.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299854/d215da2f-3a31-a26b-86c6-a9e08e46cde1.png)
- 左上の3本線のアイコンをクリックすると下の画像のようになることを確認する。
    - ![drawer.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299854/863649cf-621f-b397-ee7d-09f648764682.png)




# 次回
ユーザー設定確認・変更ページ