Help us understand the problem. What is going on with this article?

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

はじめに

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

基本設定

Vuetify インストール

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

Vuetify を import する

main.ts(main.js) 内でもいいですし、 /plugin ディレクトリを作って vutify.ts(vuetify.js) みたいなファイルを作成してもいいです。
ここでは後者の方法で 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"
  }
})
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-rowv-col を使います。
v-row は行、 v-col はセルを表します。また行は12分割して考えます。

<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
3の大きさを持った v-col が左上詰めで描画されています。

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

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

<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
青いブロックが上下左右中央に描画されています。

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

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

prop width
cols(xs) < 600px
sm 600px > < 960px
md 960px > < 1264px※
lg 1264px※ > < 1904px※
xl > 1904px※

※ -16px on Desktop

<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
またすべてのpropを指定する必要がない場合もあります。
指定がない場合は指定してるpropの一番大きいサイズの設定がそれ以上の設定となります。
例えば、propに cols=12 sm=8 を渡した場合はsm以上の大きさは8になります。
また cols=12 md=6 を渡した場合は、xsとsmは12、md以上の大きさは6になります。
このように要素の大きさをレスポンシブに変更したいしきい値のpropだけ渡せばいいです。

モーダルを使いたい

ポップアップでモーダルウィンドウを表示したい。みたいなことありませんか?
モーダルウィンドウの表示/非表示やオーバーレイも必要になったりと、結構やること多いですよね…
そんなときに便利なのが v-dialog です。これを使えばこんな感じのモーダルウィンドウを生成してくれます。しかも一緒にオーバーレイも生成してくれて、そのオーバーレイをクリックするとモーダルウィンドウを閉じてくれます。
image.png
使い方は v-dialog に対して v-model を渡して、その値がtrueなら表示、falseなら非表示といった感じになります。

<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 をそれぞれ渡します。
書き方はこんな感じです。

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>
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
すでにこの状態で各項目に対してソートすることができますし、10件ずつにページネーションしてくれています。まぁ便利。
ここからちょっと踏み込んだ設定を紹介していきます。

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

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

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に sortBysortDesc を持たせます。
次の例では age に対して昇順でソートするように指定してます。

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" }
      ]
    }
  }
})
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を渡すことでアレンジすることができます。

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

カレンダーを使いたい

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

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

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

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

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 に対応する国情報を入れます。

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

さいごに

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

is_ryo
(IoTチョットワカル)フロントエンドエンジニア。 Vue.js / AWS / GraphQL / Serverless
https://is-ryo.com
acall
ACALLは、「Life in Work and Work in Life for Happiness」をVISIONとして、どこでも安心・安全・快適なワークスタイルを実現するワークスペース管理プラットフォーム「WorkstyleOS」を開発・提供しています。オフィスワークとリモートワークのベストミックスを通じて、人々の「くらし」と「はたらく」を自由にデザインできる世界を目指します。
https://www.workstyleos.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away