Vuetify2.x でよく使うUIComponents まとめ

# はじめに

普段から Vue のUIコンポーネントフレームワークとして **Vuetify** を使っています。
Vuetify にはかなりたくさんのコンポーネントが用意されていて、うまく使いこなすことができればほとんど CSS を書く必要がなくなります。(ほんとに細かいところは CSS 書くしかありませんが…)
そんな Vuetify ですがよく使う UICompoonents をまとめていこうと思います。

## 基本設定

### Vuetify インストール

```terminal
$ yarn add vuetify @mdi/font material-design-icons-iconfont
```

### Vuetify を import する

`main.ts(main.js)` 内でもいいですし、 `/plugin` ディレクトリを作って `vutify.ts(vuetify.js)` みたいなファイルを作成してもいいです。
ここでは後者の方法で TypeScript で書く方法紹介していきます。

```typescript:plugin/vuetify.ts
import Vue from "vue"
import Vuetify from "vuetify"
import "vuetify/dist/vuetify.min.css"
// フォント関係
import "@mdi/font/css/materialdesignicons.css"
import "material-design-icons-iconfont/dist/material-design-icons.css"
// 言語設定
import ja from "vuetify/src/locale/ja"

Vue.use(Vuetify)

export default new Vuetify({
  icons: {
    iconfont: "md" || "mdi"
  },
  lang: {
    locales: { ja },
    current: "ja"
  }
})
```

```typescript:main.ts
import Vue from "vue"
import App from "./App.vue"
import router from "./router"
import store from "./store"
import vuetify from "./plugins/vuetify"
import "./registerServiceWorker"

Vue.config.productionTip = false

new Vue({
  router,
  store,
  vuetify, // ← ここに追加しないといけない
  render: (h: any): any => h(App)
}).$mount("#app")

```

## Gridデザインにしたい

`v-row` と `v-col` を使います。
`v-row` は行、 `v-col` はセルを表します。また行は12分割して考えます。

```html
<v-row class="blue lighten-4" style="height: 450px;">
  <v-col cols=3 v-for="n in 3" :key="n">
    <v-card color="blue" outlined tile height=150></v-card>
  </v-col>
</v-row>
```

これで描画されるのはこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95875/4799607a-9f49-085e-3197-3a08a6a648f4.png)
3の大きさを持った `v-col` が左上詰めで描画されています。

## 要素を上下左右中央寄せにしたい

青いブロックが左上に固まっているのを上下左右中央寄せします。
左右中央にするためには `v-row` に `justify="center"` を渡します。
上下中央にするためには `v-row` に `align-content="center"` を渡します。

```html
<v-row
  class="blue lighten-4" style="height: 450px;"
  justify="center" align-content="center"
>
  <v-col cols=3 v-for="n in 3" :key="n">
    <v-card color="blue" outlined tile height=150></v-card>
  </v-col>
</v-row>
```

これで描画されるのはこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95875/605de015-4077-0b1f-1b0b-329c0361de51.png)
青いブロックが上下左右中央に描画されています。

## Gridをレスポンシブにしたい

先程の青いブロックの大きさは、画面の幅ごとに変化させることができます。
そのためには `v-col` に対してそれぞれに対応する prop を渡す必要があります。
デフォルトの対応表はこんな感じです。

| prop | width |
|---|---|
| cols(xs) | < 600px |
| sm | 600px > < 960px |
| md | 960px > < 1264px※ |
| lg | 1264px※ > < 1904px※ |
| xl | > 1904px※ |
※　-16px on Desktop

```html
<v-row
  class="blue lighten-4" style="height: 450px;"
  justify="center" align-content="center"
>
  <v-col
    v-for="n in 3" :key="n"
    cols=12 sm=10 md=8 lg=4 xl=3
  >
    <v-card color="blue" outlined tile height=150></v-card>
  </v-col>
</v-row>
```

これである一定の画面幅より短くなるとこのようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95875/f740eb73-0f74-813a-a199-bbdebe1c543a.png)
またすべてのpropを指定する必要がない場合もあります。
指定がない場合は指定してるpropの一番大きいサイズの設定がそれ以上の設定となります。
例えば、propに `cols=12 sm=8` を渡した場合はsm以上の大きさは8になります。
また `cols=12 md=6` を渡した場合は、xsとsmは12、md以上の大きさは6になります。
このように要素の大きさをレスポンシブに変更したいしきい値のpropだけ渡せばいいです。

## モーダルを使いたい

ポップアップでモーダルウィンドウを表示したい。みたいなことありませんか？
モーダルウィンドウの表示/非表示やオーバーレイも必要になったりと、結構やること多いですよね…
そんなときに便利なのが `v-dialog` です。これを使えばこんな感じのモーダルウィンドウを生成してくれます。しかも一緒にオーバーレイも生成してくれて、そのオーバーレイをクリックするとモーダルウィンドウを閉じてくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95875/94a93c55-e2e1-c7ba-b9dc-ff44c3d30e2b.png)
使い方は `v-dialog` に対して `v-model` を渡して、その値がtrueなら表示、falseなら非表示といった感じになります。

```html
<v-container class="mt-12">
  <v-dialog v-model="dialog" width=500>
    <v-card>
      <v-card-title>Modal Title</v-card-title>
      <v-divider></v-divider>
      <v-card-text>
        <v-sheet class="pa-3">
          <div class="body-1">Modal Text</div>
        </v-sheet>
      </v-card-text>
    </v-card>
  </v-dialog>
</v-container>
```

## Tableを描画したい

Table を描画するときに便利なのが `v-data-table` です。
`v-data-table` に対して prop でヘッダーを描画するために `:headers` を、テーブルの中身は `:items` をそれぞれ渡します。
書き方はこんな感じです。

```html:template.html
<v-container class="mt-12">
  <v-row class="mt-6" justify="center">
    <v-data-table :headers="tableHeaders" :items="tableItems"></v-data-table>
  </v-row>
</v-container>
```

```typescript:script.ts
import Vue from "vue"

export default Vue.extend({
  data() {
    return {
      tableHeaders: [
        { text: "Name", value: "name" },
        { text: "Age", value: "age" },
        { text: "Gender", value: "gender" }
      ],
      tableItems: [
        { name: "Taro", age: 20, gender: "Male" },
        { name: "Hanako", age: 18, gender: "Female" },
        { name: "Ichiro", age: 25, gender: "Male" }
      ]
    }
  }
})
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95875/3162bfed-ef9e-c783-1e90-5a9b088771ba.png)
すでにこの状態で各項目に対してソートすることができますし、10件ずつにページネーションしてくれています。まぁ便利。
ここからちょっと踏み込んだ設定を紹介していきます。

### ソートの可否を指定したい

ソートの可否を設定するためには、 `:headers` に渡している値(ここでは `tableHeaders`)で `sortable` を指定します。ちなみに何も指定しないとソート可能項目となります。なので、基本的にはソートしたくない項目に対して `sortable: false` を持たせていきます。

```typescript
import Vue from "vue"

export default Vue.extend({
  data() {
    return {
      // Name と Gender でソートできないようにする
      tableHeaders: [
        { text: "Name", value: "name", sortable: false },
        { text: "Age", value: "age" },
        { text: "Gender", value: "gender", sortable: false }
      ],
      tableItems: [
        { name: "Taro", age: 20, gender: "Male" },
        { name: "Hanako", age: 18, gender: "Female" },
        { name: "Ichiro", age: 25, gender: "Male" }
      ]
    }
  }
})
```

### デフォルトでソートをかけたい

テーブルを生成した段階であるキーに対してソートをかけたいときは、optionに `sortBy` と `sortDesc` を持たせます。
次の例では `age` に対して昇順でソートするように指定してます。

```typescript
import Vue from "vue"

export default Vue.extend({
  data() {
    return {
      tableHeaders: [
        { text: "Name", value: "name", sortable: false },
        { text: "Age", value: "age" },
        { text: "Gender", value: "gender", sortable: false }
      ],
      // ここで sortBy と sortDesc を指定する
      tableOptions: {
        sortBy: ["age"],
        sortDesc: [false]
      },
      tableItems: [
        { name: "Taro", age: 20, gender: "Male" },
        { name: "Hanako", age: 18, gender: "Female" },
        { name: "Ichiro", age: 25, gender: "Male" }
      ]
    }
  }
})
```

```html:template.html
<v-container class="mt-12">
  <v-row class="mt-6" justify="center">
    <v-data-table
      :headers="tableHeaders" :items="tableItems"
      :options.sync="tableOptions"
    ></v-data-table>
  </v-row>
</v-container>
```

### ページネーションの件数をアレンジしたい

デフォルトでは10件ごとにページネーションするようになっていて、またその件数は「5 / 10 / 15 / all」という選択肢になっています。
まずデフォルトでページネーションする件数については `:items-per-page` というpropを、選択できる件数については `:footer-props` というpropを渡すことでアレンジすることができます。

```html:template.html
<v-container class="mt-12">
  <v-row class="mt-6" justify="center">
    <v-data-table
      :headers="tableHeaders" :items="tableItems"
      :items-per-page=25
      :footer-props="{itemsPerPageOptions: [25, 50, 100, -1]}"
    ></v-data-table>
  </v-row>
</v-container>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95875/f9d18881-1cb4-b752-03dc-48ce7f34ce11.png)

## カレンダーを使いたい

`v-date-picker` を使うと簡単にカレンダーを表示することができます。

```html:template.html
<v-container class="mt-12">
  <v-row class="mt-6" justify="center">
    <v-date-picker color="green" locale="en"></v-date-picker>
  </v-row>
</v-container>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95875/23c73e73-6c58-f21a-3331-28a3dd947b8b.png)

### 選択した日付を取得したい

カレンダーで選択した日付を取得したい場合は `v-model` で取得することができます。

```html:template.html
<v-container class="mt-12">
  <v-row class="mt-6" justify="center">
    <v-date-picker v-model="selectDate" color="green" locale="en"></v-date-picker>
    <v-col cols=12>
      <div>{{ selectDate }}</div>
    </v-col>
  </v-row>
</v-container>
```

### カレンダーの言語を変更したい

言語を変更したい場合は `locale` に対応する国情報を入れます。

```html:template.html
<v-container class="mt-12">
  <v-row class="mt-6" justify="center">
    <v-date-picker v-model="selectDate" color="green" locale="ja"></v-date-picker>
    <v-col cols=12>
      <div>{{ selectDate }}</div>
    </v-col>
  </v-row>
</v-container>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95875/7a0a57bf-8546-8144-927f-893e5998036e.png)

## さいごに

多分これからも増えていくと思うので随時更新していこうと思います…
ではまた！！！