フロントフレームワークであるVue.js+Vuetify導入 2章


[フロントフレームワークであるVue.js+Vuetify導入](https://qiita.com/kaorunix/items/5823f74a03ba24f804d5)
の続き

メニューを作る前に足並みを揃えるためgitのリポジトリでメニューの雛形があるコミットをチェックアウトしてください。こちらはtagをつけているためtagからチェックアウトできます。
プロジェクトトップディレクトリで、Git Bashまたはターミナルを開き次のコマンドを入れます。

```
git checkout -f step4
```

# Vuetifyでメニューを作る

git cloneをすると、以前のソースと以下の箇所が異なっています。\<v-navigation-drawer\>の中身と、\<script\>タグです。
\<script\>タグはメニューのリストです。
\<v-navigation-drawer\>タグにはメニューのリストを\<v-list\>で実装しました。メニュー名を{{}}で囲まれたmain_menu_item.nameから取得しています。

```src/App.vue
...
    <v-navigation-drawer
    v-model="drawer"
    app
    clipped>
      <v-container>
        <v-list-item>
      メニュー
        </v-list-item>
        <v-divider/>
        <v-list dense nav>
          <v-list-item v-for="main_menu_item in main_menu"
          :key="main_menu_item.name">
            <v-list-item-content>
              <v-list-item-title>
                {{ main_menu_item.name }}
              </v-list-item-title>
            </v-list-item-content>
          </v-list-item>
        </v-list>
      </v-container>
    </v-navigation-drawer>

...
<script>
export default {
  data () {
    return {
      drawer: null,
      company_menu: [
        '会社紹介',
        '沿革',
        '連絡先'
      ],

      main_menu: [
        { name: 'member1', icon: 'mdi-vuetify' },
        { name: 'member2', icon: 'mdi-cards-spade' },
        { name: 'member3', icon: 'mdi-cat' },
        { name: 'member4', icon: 'mdi-paperclip' },
        { name: 'member5', icon: 'mdi-horseshoe' },
        { name: 'member6', icon: 'mdi-scale-balance' }
      ]

    }
  }
}
</script>

```

これでメニューが表示される様になりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284697/db979d00-f61a-55e0-b9a8-1be2f1d44b89.png)

\<script\>タグの中に追加した、main_menuのメンバ(icon)はアイコンです。Vuetifyで標準で入っているアイコンは[Material Design Icons5.4.55](https://cdn.materialdesignicons.com/5.4.55/)です。
アイコンは他にも多数存在し、npmでインストールして利用することもできます。

それではアイコンを表示してみましょう。アイコン表示には<v-icon>タグの中にアイコンのコードが出力される表示される様です。

```src/App.vue
...
          <v-list-item v-for="main_menu_item in main_menu"
          :key="main_menu_item.name">
            <v-list-item-icon>
              <v-icon>{{ main_menu_item.icon }}</v-icon>
            </v-list-item-icon>
            <v-list-item-content>
...
```

次は各メニューが多段階層になることを想定してサブメニューを作っていきます。
\<script\>タグの中のmain_menuを、次の様に変更します。

```src/App.vue
      main_menu: [
        {
          name: 'member1',
          icon: 'mdi-vuetify',
          lists: [
            { name: 'Project'}, 
            { name: 'Personal'}
          ]
        },
        {
          name: 'member2',
          icon: 'mdi-cards-spade',
          lists: [
            { name: 'Project'}, 
            { name: 'Personal'}
          ]
        },
        {
          name: 'member3',
          icon: 'mdi-cat',
          lists: [
            { name: 'Project'}, 
            { name: 'Personal'}
          ]
        },
        {
          name: 'member4',
          icon: 'mdi-paperclip',
          lists: [
            { name: 'Project'}, 
            { name: 'Personal'}
          ]
        },
        {
          name: 'member5',
          icon: 'mdi-horseshoe',
          lists: ['Project', 'Personal']
        },
        {
          name: 'member6',
          icon: 'mdi-scale-balance',
          lists: [
            { name: 'Project'}, 
            { name: 'Personal'}
          ]
        }
      ]
```

\<v-list-item\>から\<v-list-group\>に変更してメニューを作っていきます。

\<template\>タグの中でslotに対してactivatorを設定することでクリックされるイベントを取得している様です。
\<template\>タグの下の\<v-list-item\>タグで子のメニューを表しています。

```src/App.vue
...
        <v-divider/>
        <v-list dense nav>

          <v-list-group v-for="main_menu_item in main_menu"
          :key="main_menu_item.name"
          :prepend-icon="main_menu_item.icon"
          no-action
          :append-icon="main_menu_item.lists ? undefined : ''">

            <template v-slot:activator>
            <v-list-item-content>
              <v-list-item-title>
                {{ main_menu_item.name }}
              </v-list-item-title>
            </v-list-item-content>
            </template>

            <v-list-item v-for="sub_menu in main_menu_item.lists"
            :key="sub_menu">
              <v-list-item-content>
                <v-list-item-title>{{ sub_menu.name }}</v-list-item-title>
              </v-list-item-content>
            </v-list-item>
          </v-list-group>
...
```

iconは\<v-icon\>タグから\<v-list-group\>タグのappend-iconに移りました。append-iconでも\<v-icon\>と同じ記法が使えます。
また、Vuetifyのドキュメントを検索してみると
[\<v-text-field\>タグ](https://vuetifyjs.com/en/api/v-text-field/#v-text-field-api)(テキスト入力フォーム)とか
[\<v-textarea\>タグ](https://vuetifyjs.com/en/components/textareas/)(テキストエリアの入力フォーム)
[\<v-sliders\>タグ](https://vuetifyjs.com/en/components/sliders/#sliders)(数値などをアナログっぽいバーで入力する)でもappend-iconがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284697/94f53e3e-dfac-f846-e780-83cd13920582.png)

# Vuetifyでメインページを作る

次にこれらのメニューが押されたらメインページを書き換える様にしましょう。

プロジェクトを作成した時に、routerというライブラリをインストールしました。これにより次のファイルができています。

`プロジェクトディレクトリ/src/router/index.js`

これはリンク先を定義するrouterというライブラリで、ここではURLに対応するコンポーネントを紐付ける働きをします。コンポーネントはVueの部品です。別々に製造したコンポーネントを組み合わすことで複雑なページや機能を実装することができます。

次のファイルでは`/`ではHomeコンポーネントを`/about`ではAboutコンポーネントを表示する設定となっています。


```src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

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

export default router
```

`/` というのはURLのことです。つまり、/にアクセスするとHome.vueの内容が表示されるということです。
でも現在はメインという文字が\<v-main\>タグの中に記述されているためHomeの中身が表示されいません。
そこで次のの様に\<v-main\>タグを書き換えてください。

```src/App.vue
...
    <v-main app>
      <router-view />
    </v-main>
...
```

\<router-view\>は、Vueの機能でdefaultのコンポーネントを表示します。
[Vue Router](https://router.vuejs.org/ja/guide/essentials/named-views.html#%E3%83%8D%E3%82%B9%E3%83%88%E3%81%95%E3%82%8C%E3%81%9F%E5%90%8D%E5%89%8D%E4%BB%98%E3%81%8D%E3%83%93%E3%83%A5%E3%83%BC)によるとdefaultの設定内容が反映される様です。
ここではindex.jsで記述されている`export default router`により
defaultが設定されている様です。そのため、`/`にアクセスするとHomeに設定されている内容が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284697/0bdfc62d-d2d1-5081-a69c-d0ba24e48df0.png)

試しに`/about`にもアクセスしてみてください。Aboutページが表示されます。

つまり、先ほど作ったメニューをクリックするとindex.jsで記載されているURLへ遷移すればメインコンテンツを書き換えることができます。

確認するためURLへの遷移を実装します。\<script\>タグ内のmember1に次の要素を足してください。

```src/App.vue
...
        {
          name: 'member1',
          icon: 'mdi-vuetify',
          lists: [
            { name: 'Project', link: '/' }, 
            { name: 'Personal' link: '/about' }
          ]
        },
...
```

linkがURLとなります。
これを描画したメニューから使うのは次のコードです。\<v-list-item\>を書き換えてループにtoプロパティにURLを設定する様にします。

```src/App.vue
...
            <v-list-item v-for="sub_menu in main_menu_item.lists"
            :key="sub_menu.name"
            :to="sub_menu.link"
            >
              <v-list-item-content>
                <v-list-item-title>{{ sub_menu.name }}</v-list-item-title>
              </v-list-item-content>
            </v-list-item>
...
```

これで次の様にサブメニューのリンクが有効になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284697/a79ff60f-6e6e-6405-e54a-33af1e223bb8.png)

クリックするとaboutページに遷移します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284697/21e1d3af-1334-aa79-a6c1-d8f7e48e6b90.png)

routerをインストールした時に作られたファイルの様に、メインページなどは別ファイルとして作ることができます。

ここからは自由に各自のページを作って行きましょう。
各自、ブランチを作って
`router/index.js` のimport文にこれから作るvueファイルのパス、routesのメンバを足してください。

次のファイルが参考となるのでコピーしてください。

```
views/Home.vue
components/HelloWorld.vue
router/index.js
```


# 作ったページを公開する

[Vue CLI deployment](https://cli.vuejs.org/guide/deployment.html#github-pages)にデプロイのやり方が載っております。

プロジェクトホームディレクトリのvue.config.jsに公開するパスを記述します。

```vue.config.js
module.exports = {
  publicPath: process.env.NODE_ENV === 'production'
    ? '/company/'
    : '/'
}
```

次にデプロイシェルを作ります。[Vue CLI deployment](https://cli.vuejs.org/guide/deployment.html#github-pages)に掲載されている内容でプロジェクトホームにdeploy.shを作成してください。

次の内容のみ自分のgithub環境に合わせて変更して、コメントアウトを外してください。

```
git push -f git@github.com:<USERNAME>/<REPO>.git master:gh-pages
```

ここでのREPOは今回のvueの開発プロジェクトとは別リポジトリをgithub上に作りそれを指定します。

vue.config.jsを変更したらdeploy.shを実行します。
コンパイルが始まりgithubにpushされます。

面白いのはプロジェクトホームは.gitignoreでdistを指定しているのでリポジトリには登録されません。ビルドするときはプロジェクトホームで作業しなければならないのでdistディレクトリができても影響ない様にしていますが、githubページとしてリポジトリ登録する必要があるのでその中もgitリポジトリとなっています。

終わったらブラウザで各自の次のURLを開いてください。

https://username.github.io/company/

これでグローバルなwebページとして公開されました。

![vue_cre_github.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284697/f9800d99-806e-63b8-fa46-8b034a59cb0a.png)


# タイトルバーのボタンにもメインページを作る

おまけですが、タイトルバーのボタンにメインページを表示してみましょう。
\<v-list-item\>を書き換えmenu_itemにname, linkを持てる様にします。toプロパティにリンク先を設定します。


```
...
      <v-list>
        <v-subheader>ヘルプ</v-subheader>
        <v-list-item v-for="menu_item in company_menu"
        :key="menu_item.name"
        :to="menu_item.link">
          <v-list-item-content>
            <v-list-item-title>{{ menu_item.name }}</v-list-item-title>
          </v-list-item-content>
        </v-list-item>
      </v-list>
...
      company_menu: [
        { name: '会社紹介', link: '/' },
        { name: '沿革', link: '/' },
        { name: '連絡先', link: '/' }
      ],
... 
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284697/add6f81e-e2cc-8209-2e3e-8a5e6dad90d5.png)

これで、「会社紹介」のメニューを押下するとトップ画面が表示される様になりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284697/25927d52-eda4-ad21-98c9-3f15fcfa3f0b.png)

これらのメニューは[Vuetifyでメインページを作る](#Vuetifyでメインページを作る)の箇所を参考に
src/router/index.jsのなかで
作成したcomponentsをimportし、画面を作っていってください。