Linux(ubuntu)環境でVue.js/Nuxt.js試行（その２：「VuetifyのUIコンポーネント」）

# お題
表題のお試し。[前回](https://qiita.com/sky0621/items/2deb95a94bd4a6bd4d72)作成したプロジェクトをベースに、[Vuetify](https://vuetifyjs.com/en/getting-started/quick-start)の各種[UIコンポーネント](https://vuetifyjs.com/en/components/api-explorer)を試していく。
今回は、create-nuxt-appで作成した時点の[デフォルトレイアウト](https://ja.nuxtjs.org/guide/views#%E3%83%AC%E3%82%A4%E3%82%A2%E3%82%A6%E3%83%88)で使われているUIコンポーネントを掘り下げていく。
それ以外のUIコンポーネントについては次回以降で。

# 対象読者
Linux(ubuntu)環境を開発用の端末に使っていて、これから`Nuxt.js`と`Vuetify`を組み合わせて使ってみようと思っている人。

# Linux(ubuntu)環境でVue.js/Nuxt.js試行Index
- [Linux(ubuntu)環境でVue.js/Nuxt.js試行（その１：「create-nuxt-app」）](https://qiita.com/sky0621/items/2deb95a94bd4a6bd4d72)

# 開発環境
### # OS
```
$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="18.04.1 LTS (Bionic Beaver)"
```

### # 依存モジュールのバージョン
`package.json`の内容より、以下の通り。

```
    "nuxt": "^2.0.0",
    "vuetify": "^1.2.4",
```

# 実践

## create-nuxt-appで作成した時点の[デフォルトレイアウト](https://ja.nuxtjs.org/guide/views#%E3%83%AC%E3%82%A4%E3%82%A2%E3%82%A6%E3%83%88)

プロジェクト作成時点のディレクトリ構造は下記（今回の説明に必要な部分のみ抜粋）

```
try001/
　〜〜【省略】〜〜
├── components
│   ├── Logo.vue
│   ├── README.md
│   └── VuetifyLogo.vue
├── layouts
│   ├── README.md
│   └── default.vue
　〜〜【省略】〜〜
├── pages
│   ├── README.md
│   ├── index.vue
│   └── inspire.vue
　〜〜【省略】〜〜
```

### プロジェクト作成時点の `layouts/default.vue` 解析

#### layouts/default.vue

```
<template>
  <v-app dark>
    〜〜【１：ナビゲーション・ドロワー】〜〜
    〜〜【２：ツールバー】〜〜
    〜〜【３：コンテンツ】〜〜
    〜〜【４：ナビゲーション・ドロワー（右）】〜〜
    〜〜【５：フッター】〜〜
  </v-app>
</template>

<script>
export default {
  data() {
    return {
　　　　〜〜省略〜〜
    }
  }
}
</script>
```

#### 実際の表示

![screenshot-localhost-3000-2019-01-09-00-46-23-717.png](https://qiita-image-store.s3.amazonaws.com/0/180599/5155ee7c-75ba-e383-7e5d-b79abc14db4c.png)

#### <v-app>

各ブロックを見ていく前に `<v-app>` を少しいじる。
デフォルトでは、 `<v-app dark>` であり、 `dark` 属性によりダークテーマが採用されている。
まずは単純にこの属性をなくしてみると、こうなる。

![screenshot-localhost-3000-2019-01-09-01-21-58-078.png](https://qiita-image-store.s3.amazonaws.com/0/180599/c65c36db-ae2d-ebfa-45dc-7b1aa6bae190.png)

で、 `<v-app>` には `light` 属性というのがあるようなので、指定してみる。 `<v-app light>`

![screenshot-localhost-3000-2019-01-09-01-26-27-207.png](https://qiita-image-store.s3.amazonaws.com/0/180599/baa2ec51-aa54-6cd0-e5be-ecd78c009a41.png)

あれっ、属性なしの `<v-app>` と変わらないな。

#### 【１：ナビゲーション・ドロワー】

参考：https://vuetifyjs.com/en/components/navigation-drawers

開閉用のコンポーネント。デフォルトでは【２：ツールバー】にあるボタン押下で開閉するよう制御されている。

![screenshot-localhost-3000-2019-01-09-09-43-14-193.png](https://qiita-image-store.s3.amazonaws.com/0/180599/c981bedd-4eb2-ffab-ba92-bc884706f61f.png)


```
    <v-navigation-drawer
      :mini-variant="miniVariant"
      :clipped="clipped"
      v-model="drawer"
      fixed
      app
    >
　　　　〜〜【スロットコンテンツ】〜〜
    </v-navigation-drawer>
```

指定されている属性群を全て取っ払って、`<v-navigation-drawer>`だけにしてみると、こうなる。
【２：ツールバー】の上に重なってしまっているし、高さも画面下部に届いていない。↓

![screenshot-localhost-3000-2019-01-10-09-25-56-300.png](https://qiita-image-store.s3.amazonaws.com/0/180599/a07658d0-8ea9-6be4-cfe1-9692222855db.png)

↑に対し、デフォルトで使われていた属性を１つ１つ追加してみる。

##### ★PROPS「`fixed`」
`fixed`は「要素を固定します」とのこと。とりあえず追加してみる。

```
    <v-navigation-drawer
      fixed
    >
```

![screenshot-localhost-3000-2019-01-10-09-33-26-128.png](https://qiita-image-store.s3.amazonaws.com/0/180599/3ad8285f-4f23-4663-b66c-23d26b0e34ca.png)

お、画面下部まで伸びた。

##### ★PROPS「`app`」
`app`は「アプリケーションレイアウトの一部としてコンポーネントを指定します。動的にコンテンツのサイズを調整するために使用されます」とのこと。

```
    <v-navigation-drawer
      fixed
      app
    >
```

![screenshot-localhost-3000-2019-01-10-09-38-41-592.png](https://qiita-image-store.s3.amazonaws.com/0/180599/707a78af-e794-7704-3783-e2795b711332.png)

【２：ツールバー】の上に重ならなくなった。

##### ★「`v-model`」
次は、ドロワーの動き（ツールバーにあるボタン押下による開閉）の制御に使われている`v-model`を追加。
これがないと（厳密には、これとツールバーにあるボタンに付けられたクリックイベント）ドロワーが開閉しない。

```
    <v-navigation-drawer
      v-model="drawer"
      fixed
      app
    >
```

##### ★PROPS「`clipped`」
`clipped`は「クリップされたドロワーはアプリケーションツールバーの下にある」とのこと。。。
う〜ん？　使用事例も載っていないし・・・。

```
    <v-navigation-drawer
      :clipped="clipped"
      v-model="drawer"
      fixed
      app
    >
```

↑で指定されている「`:clipped="clipped"`」の左辺の「`:`」は「`v-on:`」の略でイベントを拾う。
「`clipped`」かどうかを右辺の「`"clipped"`」変数（イベントと同じ変数名にしてるからややこしいのか？）から判断。つまり、`boolean` 値。
これは下記のように初期化されている。

```
<script>
export default {
  data() {
    return {
      clipped: false,
　　　　　〜省略〜
    }
  }
}
</script>
```

この `clipped` のフラグ切り替えを【２：ツールバー】が担っている様子。
よって、挙動の解析は後述。

##### ★PROPS「`mini-variant`」
`mini-variant`は「ナビゲーションドロワーの幅を縮小し、.sync修飾子も受け入れます。これをクリックすると、引き出しが再び開きます。」とのこと。
デフォルト事例では「`.sync`」は付いていない。単純に幅が縮小される？

```
    <v-navigation-drawer
      :mini-variant="miniVariant"
      :clipped="clipped"
      v-model="drawer"
      fixed
      app
    >
```

↑で指定されている「`:mini-variant="miniVariant"`」については`clipped`の説明と同様で、
`boolean` 値の`miniVariant`変数から判断。
これは下記のように初期化されている。

```
<script>
export default {
  data() {
    return {
　　　　　〜省略〜
      miniVariant: false,
　　　　　〜省略〜
    }
  }
}
</script>
```

この `miniVariant` のフラグ切り替えもやはり【２：ツールバー】が担っている様子。
よって、これも、挙動の解析は後述。

ちなみに、「`.sync`」を使った事例は下記に載っていた。
https://vuetifyjs.com/en/components/navigation-drawers#mini

##### 【スロットコンテンツ】
Vue.jsにおけるスロットコンテンツ自体については下記参照。
https://jp.vuejs.org/v2/guide/components-slots.html

```
<my-component>
    <slot></slot>
</my-component>
```

という形でコンポーネント定義しておくと、呼び出し側で

```
<my-component>
    <div>ABCDE</div>
</my-component>
```

というようにタグ（別コンポーネントも可）が入れられるようになるもの。

さて、デフォルトレイアウトにおける`<v-navigation-drawer>`のスロットコンテンツとしては下記が定義されている。

```
      <v-list>
        <v-list-tile
          v-for="(item, i) in items"
          :to="item.to"
          :key="i"
          router
          exact
        >
          <v-list-tile-action>
            <v-icon v-html="item.icon" />
          </v-list-tile-action>
          <v-list-tile-content>
            <v-list-tile-title v-text="item.title" />
          </v-list-tile-content>
        </v-list-tile>
      </v-list>
```

`items`の内容をループ表示している。
`items`の内容は下記。

```
      items: [
        { icon: 'apps', title: 'Welcome', to: '/' },
        { icon: 'bubble_chart', title: 'Inspire', to: '/inspire' }
      ],
```

##### [Material Design Icons](https://material.io/tools/icons/?style=baseline)

上記で `items` に使われている `icon: 'apps'` と `icon: 'bubble_chart'` は下記で用意されているものからピックアップされている。
https://material.io/tools/icons/?icon=terrain&style=baseline
`icon`属性については下記参照。
https://vuetifyjs.com/ja/components/icons

#### 【２：ツールバー】

参考： https://vuetifyjs.com/ja/components/toolbars

サイトナビゲーションとして使われる。前述のナビゲーションドロワーと連携した使い方も有用。

```
    <v-toolbar
      :clipped-left="clipped"
      fixed
      app
    >
      <v-toolbar-side-icon @click="drawer = !drawer" />
      <v-btn
        icon
        @click.stop="miniVariant = !miniVariant"
      >
        <v-icon v-html="miniVariant ? 'chevron_right' : 'chevron_left'" />
      </v-btn>
      <v-btn
        icon
        @click.stop="clipped = !clipped"
      >
        <v-icon>web</v-icon>
      </v-btn>
　　　　〜〜【以降、省略】〜〜
    </v-toolbar>
```

`fixed`と`app`は前述の通りなので省略。

##### `:clipped-left="clipped"`

前述した通りだけど、【１：ナビゲーション・ドロワー】は`:clipped="clipped"`とあり、`clipped`のオンオフで制御されるようになっている。
これが、【２：ツールバー】が持つ`:clipped-left="clipped"`と、どう絡むのか？　やってみる。
`"clipped"`のオンオフ切り替えは↓

```
      <v-btn
        icon
        @click.stop="clipped = !clipped"
      >
        <v-icon>web</v-icon>
      </v-btn>
```

■初期表示
![screenshot-localhost-3000-2019-01-16-16-04-47-299.png](https://qiita-image-store.s3.amazonaws.com/0/180599/9dde5deb-b6e7-8404-d4e9-1e17370b28e1.png)

■Webアイコンタップ後
![screenshot-localhost-3000-2019-01-16-16-07-31-765.png](https://qiita-image-store.s3.amazonaws.com/0/180599/50987dbf-8fbc-f1b3-8cb9-4e05d60b5921.png)

覆い被さるとはちょっと違うかな。こういうのをクリップされたと言う？

##### `:mini-variant="miniVariant"`

前述した通りだけど、【１：ナビゲーション・ドロワー】は`:mini-variant="miniVariant"`とあり、`miniVariant`のオンオフで制御されるようになっている。
これが、【２：ツールバー】に含まれるボタンによるオンオフ切り替え（↓）と、どう絡むのか？　やってみる。
`"clipped"`のオンオフ切り替えは↓

```
      <v-btn
        icon
        @click.stop="miniVariant = !miniVariant"
      >
        <v-icon v-html="miniVariant ? 'chevron_right' : 'chevron_left'" />
      </v-btn>
```

■初期表示
![screenshot-localhost-3000-2019-01-16-16-16-45-468.png](https://qiita-image-store.s3.amazonaws.com/0/180599/0cb71ba4-edea-a120-add6-8f59a9b93d8f.png)


■「<」アイコンタップ後
![screenshot-localhost-3000-2019-01-16-16-17-45-025.png](https://qiita-image-store.s3.amazonaws.com/0/180599/ea4b99b3-9d59-be75-d9c1-dd5118d49e3b.png)

なるほど。幅が縮小された！

#### 【３：コンテンツ】

コンテンツは下記の通り、ページコンポーネント(`/pages`配下のvueファイル)を読み込むだけ。

参考： https://ja.nuxtjs.org/api/components-nuxt/

```
    <v-content>
      <v-container>
        <nuxt />
      </v-container>
    </v-content>
```

`/pages`直下には`index.vue`が存在する。中身は↓（一部省略）

```
<template>
  <v-layout
　　〜省略〜
  >
    <v-flex
　　　〜省略〜
    >
      <div class="text-xs-center">
        <logo/>
        <vuetify-logo/>
      </div>
      <v-card>
　　　　〜省略〜
      </v-card>
    </v-flex>
  </v-layout>
</template>
```

ちょうど↑で表現されるビューが↓

![screenshot-localhost-3000-2019-01-16-16-44-40-217.png](https://qiita-image-store.s3.amazonaws.com/0/180599/44e09299-6d3b-605d-0653-75c950b617ff.png)

`<v-card>`要素配下は次回以降、掘り下げていこう。
`<logo/>`と`<vuetify-logo/>`はコンポーネント。
以下のようにインポートしている。

```
<script>
import Logo from '~/components/Logo.vue'
import VuetifyLogo from '~/components/VuetifyLogo.vue'

export default {
  components: {
    Logo,
    VuetifyLogo
  }
}
</script>
```

#### 【４：ナビゲーション・ドロワー（右）】

使われているPROPSには違うものがあるもののナビゲーションドロワーは説明済みなので省略。

#### 【５：フッター】

参考： https://vuetifyjs.com/en/components/footer

ユーザーがサイト内の任意のページからアクセスしたいと思う可能性がある一般的な情報を表示するために使用される。

```
    <v-footer
      :fixed="fixed"
      app
    >
      <span>&copy; 2017</span>
    </v-footer>
```

ここはあえて説明なしでもいいかな。

# まとめ
デフォルトのレイアウトだけでも、ふんだんに Vuetify の UIコンポーネントが活用されている。
次回は、まっさらな状態から、各種UIコンポーネントを少しずつ使い倒してみよう。