Vuetify3 でよく使うコンポーネントのメモ（２）

このページは下記リンク先へ移行中です。

- [Vuetify3 の基本](https://zenn.dev/books/vuetify3_book/edit)

以下の記事は内容が古い可能性があります。新しい情報については上記記事を参照してください。

# 内容

このページには、Vuetify3 の下記のコンポーネントについての覚書きがあります。

- [v-list / v-list-item](https://qiita.com/mml/items/16030c4404b4a814956b#%E3%83%AA%E3%82%B9%E3%83%88%E3%81%A8%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB)
- [v-table](https://qiita.com/mml/items/16030c4404b4a814956b#%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB-v-table)
- [v-carousels](https://qiita.com/mml/items/16030c4404b4a814956b#%E8%A4%87%E6%95%B0%E3%81%AE%E7%94%BB%E9%9D%A2%E3%82%92%E3%82%B9%E3%83%A9%E3%82%A4%E3%83%89%E3%82%B7%E3%83%A7%E3%83%BC%E3%81%AE%E3%82%88%E3%81%86%E3%81%AB%E5%88%87%E3%82%8A%E6%9B%BF%E3%81%88%E3%82%8B-v-carousels)
- [v-tabs](https://qiita.com/mml/items/16030c4404b4a814956b#%E8%A4%87%E6%95%B0%E3%81%AE%E7%94%BB%E9%9D%A2%E3%82%92%E3%82%BF%E3%83%96%E3%81%A7%E5%88%87%E3%82%8A%E6%9B%BF%E3%81%88%E3%82%8B-v-tabs)
- [v-pagenation](https://qiita.com/mml/items/16030c4404b4a814956b#%E5%A4%A7%E9%87%8F%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E4%B8%80%E5%AE%9A%E3%81%AE%E5%80%8B%E6%95%B0%E3%81%94%E3%81%A8%E3%81%AB%E3%83%9A%E3%83%BC%E3%82%B8%E3%81%AB%E5%88%86%E3%81%91%E3%81%A6%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B-v-pagination)
- [v-progress-circle / v-progress-linear](https://qiita.com/mml/items/16030c4404b4a814956b#v-progress-circle--v-progress-linear)
- [v-divider](https://qiita.com/mml/items/16030c4404b4a814956b#%E4%BB%95%E5%88%87%E3%82%8A%E3%81%AB%E4%BD%BF%E3%81%88%E3%82%8B%E6%A8%AA%E7%B7%9A-v-divider)
- [v-toolbar](https://qiita.com/mml/items/16030c4404b4a814956b#%E3%83%84%E3%83%BC%E3%83%AB%E3%83%90%E3%83%BC-v-toolbar)
- [v-spacer](https://qiita.com/mml/items/16030c4404b4a814956b#%E6%A8%AA%E6%96%B9%E5%90%91%E3%81%AE%E7%A9%BA%E7%99%BD-v-spacer)

# 関連記事

- [Vuetify3 のレイアウトに関するメモ](https://qiita.com/mml/items/7bdffe5eb5044f861cf1)
- [Vuetify3 でよく使うコンポーネントのメモ（１）](https://qiita.com/mml/items/ec0a4c63f9d29d8c0203)
- [Vuetify3 でよく使うコンポーネントのメモ（２）](https://qiita.com/mml/items/16030c4404b4a814956b)
- Vuetify3 Labs
-- [DatePicker](https://qiita.com/mml/items/2c99fa3fcfebd4979bc3)
-- [DataTable](https://qiita.com/mml/items/ae334f79f14469efccf0)

# リストとテーブル

## リスト (v-list / v-list-item)

複数の項目を行で並べて表示します。HTML の ul/li 要素の見た目を綺麗にした感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/19776b69-9686-89cf-df60-b947a53a8024.png)

コード：

```App.vue
<template>
  <v-container>
    <v-list>
      <v-list-item>
        <v-list-item-tile>HOGE1</v-list-item-tile>
      </v-list-item>
      <v-list-item>
        <v-list-item-tile>HOGE2</v-list-item-tile>
      </v-list-item>
      <v-list-item>
        <v-list-item-tile>HOGE3</v-list-item-tile>
      </v-list-item>
    </v-list>
  </v-container>
</template>
```


### InnerText と v-lite-item-title の違い

リファレンスのページを見ると、`v-list-item-title` を使うように書かれているのですが、使わなくても表示が変わらない気がします。ただ、いずれ変更があるかもしれないので、`v-list-item-title` を使っておいたほうがよさそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/613c9f41-3bf6-f2b5-2c32-3ae8acce5fdb.png)

コード：

```App.vue
<template>
  <div class="d-flex">
  <v-container>
    <v-list>
      <v-list-item>HOGE1</v-list-item>
      <v-list-item>HOGE2</v-list-item>
      <v-list-item>HOGE3</v-list-item>
    </v-list>
    InnerText
  </v-container>

  <v-container>
    <v-list>
      <v-list-item>
        <v-list-item-title>HOGE1</v-list-item-title>
      </v-list-item>
      <v-list-item>
        <v-list-item-title>HOGE2</v-list-item-title>
      </v-list-item>
      <v-list-item>
        <v-list-item-title>HOGE3</v-list-item-title>
      </v-list-item>
    </v-list>
    v-list-item-title
  </v-container>

  <v-container>
    <v-list>
      <v-list-item>HOGE1
        <v-list-item-subtitle>foobar</v-list-item-subtitle>
      </v-list-item>
      <v-list-item>HOGE2
        <v-list-item-subtitle>foobar</v-list-item-subtitle>
      </v-list-item>
      <v-list-item>HOGE3
        <v-list-item-subtitle>foobar</v-list-item-subtitle>
      </v-list-item>
    </v-list>
    InnerText + v-list-item-subtitle
  </v-container>

  <v-container>
    <v-list>
      <v-list-item>
        <v-list-item-title>HOGE1</v-list-item-title>
        <v-list-item-subtitle>foobar</v-list-item-subtitle>
      </v-list-item>
      <v-list-item>
        <v-list-item-title>HOGE2</v-list-item-title>
        <v-list-item-subtitle>foobar</v-list-item-subtitle>
      </v-list-item>
      <v-list-item>
        <v-list-item-title>HOGE3</v-list-item-title>
        <v-list-item-subtitle>foobar</v-list-item-subtitle>
      </v-list-item>
    </v-list>
    v-lite-item-title + v-list-item-subtitle
  </v-container>

  </div>
</template>
```

### クリックされた項目の値を取得する

`value` 属性を付けると、クリックできるようになります。クリックした `v-lite-item` の `value` の値は、`v-list` の `@change:select` で取得できます。

![list1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/7d882eb1-6b99-6c9f-119b-1b338fd77171.gif)

コード：

```App.vue
<template>
  <v-container>
    <v-list @click:select="clickItem">
      <v-list-item value="1">
        <v-list-item-title>HOGE1</v-list-item-title>
      </v-list-item>
      <v-list-item value="2">
        <v-list-item-title>HOGE2</v-list-item-title>
      </v-list-item>
      <v-list-item value="3">
        <v-list-item-title>HOGE3</v-list-item-title>
      </v-list-item>
    </v-list>
    <h1>{{ message }}</h1>
  </v-container>
</template>
<script>
export default {
  data: () => ({
    message: ""
  }),
  methods: {
    clickItem(arg)
    {
      this.message = arg.id;
    }
  }
}
</script>
```

### 配列による生成

`v-list` は `items` 属性を使って、配列から生成するほうが楽です。生成する元となる配列を `:items` で指定します。`item-title` で `v-list-item-title` を生成するためのプロパティを、`item-subtitle` で `v-list-item-subtitle` を生成するためのプロパティをそれぞれ指定します。`item-value` は `v-list-item` をクリックしたときに取得できる値を生成するためのプロパティを指定します。

動作自体は、上の例と全く同じになります。

![list1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/7d882eb1-6b99-6c9f-119b-1b338fd77171.gif)

コード：

```App.vue
<template>
  <v-container>
    <v-list 
      @click:select="clickItem"
      :items="listItems"
      item-title="name"
      item-value="id"
    >
    </v-list>
    <h1>{{ message }}</h1>
  </v-container>
</template>
<script>
export default {
  data: () => ({
    listItems: [
        {
          name: "Hoge1",
          id: 1
        },
        {
          name: "Hoge2",
          id: 2
        },
        {
          name: "Hoge3",
          id: 3
        },
    ],
    message: ""
  }),
  methods: {
    clickItem(arg)
    {
      this.message = arg.id;
    }
  }
}
</script>
```

`v-list` はオプションが豊富で、いろんなことができます。

![list2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/468b7288-d2cd-1329-2d98-e0e959d98bfd.gif)

リストの途中にサブタイトルをつけたり、アイコンを付けたり、仕切り線を付けたり、クリックしたときの色をかえたりできます。

```App.vue
<template>
  <v-container>
    <v-list
      @click:select="clickItem"
      :items="listItems"
      item-title="name"
      item-value="id"
    >
    </v-list>
    <h1>{{ message }}</h1>
  </v-container>
</template>
<script>
export default {
  data: () => ({
    listItems: [
        { type: 'subheader', name: 'Group #1' },
        {
          name: "Hoge1",
          id: 1,
          props: {
            prependIcon: 'mdi-home',
            color: "red"
          },
        },
        {
          props: {
            prependIcon: 'mdi-file',
          },
          name: "Hoge2",
          id: 2
        },
        { type: 'divider', inset: true },
        { type: 'subheader', name: 'Group #2' },
        {
          props: {
            appendIcon: 'mdi-home',
          },
          name: "Hoge3",
          id: 3
        },
        {
          icon: "mdi-home",
          name: "Hoge4",
          id: 4
        },
    ],
    message: ""
  }),
  methods: {
    clickItem(arg)
    {
      this.message = arg.id;
    }
  }
}
</script>
```

入れ子になったリスト（サブリスト）を作ることもできます。詳しくは、公式のドキュメントを見てください。

- [Lists](https://next.vuetifyjs.com/en/components/lists/)

なお、リストは単体で使われることもありますが、他のコンポーネントの一部として使われることも多いです。代表的なものは、下記です。

- `v-navigation-drawer`
- `v-menu`

`v-menu` については下記の「メニュー」の項目を見てください。

- [Vuetify3 でよく使うコンポーネントのメモ（１）](https://qiita.com/mml/items/ec0a4c63f9d29d8c0203)

`v-navigation-drawer` については、`nav` 属性を付けてフォントが少し小さいリストを使うことが多いです。

![list4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/69c1dc61-268b-bc14-f643-a50f2bb42582.gif)

コード：

```App.vue
<template>
  <v-container>
    <v-layout>
      <v-btn @click="drawer = !drawer">
        Navigator
      </v-btn>

      <v-navigation-drawer v-model="drawer">
        <v-list 
          nav
          density="compact"
          :items="listItems"
          item-title="name"
          item-value="id"
        >
        </v-list>
      </v-navigation-drawer>
    </v-layout>
  </v-container>
</template>
<script>
export default {
  data: () => ({
    drawer: false,
    listItems: [
      { type: 'header', name: 'Main Menu' },
      { type: 'divider', inset: true },
      {
        name: "Home",
        id: 1,
        props: {
          prependIcon: 'mdi-home',
        },
      },
      {
        name: "File",
        id: 2,
        props: {
          prependIcon: 'mdi-file',
        },
      },
    ]
  }),
}
</script>
```

max-height を指定すると、指定された高さからリストの項目があふれると、自動的にスクロールバーがつきます。

![list5.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/f72fc8eb-149c-b772-e5d5-8c0eac4a1851.gif)

コード：

```App.vue
<template>
  <v-container>
      <v-list
        :items="listItems"
        item-title="name"
        item-value="id"
        max-height="200"
      >
      </v-list>
  </v-container>
</template>
<script>
export default {
  data: () => ({
    listItems: [
      { name: "Home1", id: 1,},
      { name: "Home2", id: 2,},
      { name: "Home3", id: 3,},
      { name: "Home4", id: 4,},
      { name: "Home5", id: 5,},
      { name: "Home6", id: 6,},
      { name: "Home7", id: 7,},
      { name: "Home8", id: 8,},
      { name: "Home9", id: 9,},
      { name: "Home10", id: 10,},
    ]
  }),
}
</script>
```

`v-list` は、どういうわけか `v-sheet` の中に置くと、`v-sheet` のサイズを超えて下側へはみ出してしまうことがあります。リストのサイズを制限したい場合は、`v-sheet` ではなく `v-card` の中に入れるようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/3081c567-f02f-e721-7592-58bf4df9e89d.png)

上の図のように、カードとシートでほぼ同等の設定にしても、ソート側は `v-list` のサイズがシートを超えると、外へはみ出します。

```App.vue
<template>
  <v-container class="d-flex">
    <v-card height="200" width="300" color="black" class="pa-3 ma-2">
      <v-card-title>CARD</v-card-title>
      <v-list
        :items="listItems"
        item-title="name"
        item-value="id"
      >
      </v-list>
    </v-card>
    <v-sheet height="200" width="300" class="pa-3 ma-2 bg-black">
      <h3 class="my-3">ShEET</h3>
      <v-list
        :items="listItems"
        item-title="name"
        item-value="id"
      >
      </v-list>
    </v-sheet>
  </v-container>
</template>
<script>
export default {
  data: () => ({
    listItems: [
      { name: "Home1", id: 1,},
      { name: "Home2", id: 2,},
      { name: "Home3", id: 3,},
      { name: "Home4", id: 4,},
      { name: "Home5", id: 5,},
      { name: "Home6", id: 6,},
      { name: "Home7", id: 7,},
      { name: "Home8", id: 8,},
      { name: "Home9", id: 9,},
      { name: "Home10", id: 10,},
    ]
  }),
}
</script>
```

## テーブル v-table

表を作ります。いくつかの値が組になっているデータの表示に便利です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/828f555d-47c9-846c-e1fe-171c150fa8ac.png)

コード：

```App.vue
<template>
  <v-container>
    <v-table>
      <thead>
        <tr>
          <th class="text-left">
            都道府県
          </th>
          <th class="text-right">
            No
          </th>
          <th class="text-right">
            面積
          </th>
        </tr>
      </thead>
      <tbody>
        <tr
          v-for="item in todohuken"
          :key="item.name"
        >
          <td>{{ item.name }}</td>
          <td class="text-right">{{ item.no }}</td>
          <td class="text-right">{{ item.area }}</td>
        </tr>
      </tbody>
    </v-table>
  </v-container>
</template>
<script>
export default {
  data () {
    return {
      todohuken: [
        {name: '北海道', no: 1,  area: 83456.20 },
        {name: '長野県', no: 2,  area: 13562.23 },
        {name: '東京都', no: 3,  area: 2187.42 },
        {name: '和歌山県', no: 4,area: 4726.12 },
        {name: '香川県', no: 5,  area: 1876.47 },
        {name: '神奈川県', no: 6,area: 2415.84 },
        {name: '岡山県', no: 7,  area: 7113.00 },
        {name: '鹿児島県', no: 8,area: 9187.80 },
        {name: '宮城県', no: 9,  area: 7285.73 },
        {name: '石川県', no: 10, area: 4185.47 },                                
      ],
    }
  },
}
</script>
```

`height` を指定すると、その高さを超えたときにスクロールバーが表示されすようになります。リストと違って、`max-height` ではうまくいきません。

`density="compact"` を指定すると、行の縦幅が少し詰まります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/4532ef2a-06b2-d1ba-deb6-3f0f10cfb4c0.png)

```App.vue
<template>
  <v-container>
    <v-table 
      height="300"
      density="compact"
    >
      <thead>
        <tr>
          <th class="text-left">
            都道府県
          </th>
          <th class="text-right">
            No
          </th>
          <th class="text-right">
            面積
          </th>
        </tr>
      </thead>
      <tbody>
        <tr
          v-for="item in todohuken"
          :key="item.name"
        >
          <td>{{ item.name }}</td>
          <td class="text-right">{{ item.no }}</td>
          <td class="text-right">{{ item.area }}</td>
        </tr>
      </tbody>
    </v-table>
  </v-container>
</template>
<script>
export default {
  data () {
    return {
      todohuken: [
        {name: '北海道', no: 1,  area: 83456.20 },
        {name: '長野県', no: 2,  area: 13562.23 },
        {name: '東京都', no: 3,  area: 2187.42 },
        {name: '和歌山県', no: 4,area: 4726.12 },
        {name: '香川県', no: 5,  area: 1876.47 },
        {name: '神奈川県', no: 6,area: 2415.84 },
        {name: '岡山県', no: 7,  area: 7113.00 },
        {name: '鹿児島県', no: 8,area: 9187.80 },
        {name: '宮城県', no: 9,  area: 7285.73 },
        {name: '石川県', no: 10, area: 4185.47 },                                
      ],
    }
  },
}
</script>
```

- [Tables](https://next.vuetifyjs.com/en/components/tables/)

## データテーブル v-data-table

v-table よりリッチな感じでデータの表示ができます。pagenation の機能がデフォルトで付いているため、データの個数を区切って少しずつ表示させことが簡単にできるのが非常に便利です。またソート機能もデフォルトでついています。フィルタ機能（検索機能）もあります。

データの表示欄についても、チェックボックをつけたり、アイコンを表示したり、いろいろできます。

なお　vuetify 3.3.6 では　Vuetify Labs として実装されています。実験段階の実装ということで、動作については保証されていません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/8e93e414-ed2e-2a9c-ca0c-d3988d2c3178.png)

```App.vue
<template>
  <v-container>
    <v-data-table
      v-model:items-per-page="itemsPerPage"
      :headers="headers"
      :items="dataset"
      item-value="name"
      class="elevation-1"
    ></v-data-table>
  </v-container>
</template>

<script>
import { VDataTable } from 'vuetify/lib/labs/components.mjs';

export default {
  data: () => ({
    itemsPerPage: 5,

    headers: [
      {
        title: '都道府県',
        align: 'start',
        sortable: false,
        key: 'name',
      },
      { title: 'no', align: 'end', key: 'no' },
      { title: '面積', align: 'end', key: 'area' },
    ],
    dataset: [
      {name: '北海道', no: 1,  area: 83456.20 },
      {name: '長野県', no: 2,  area: 13562.23 },
      {name: '東京都', no: 3,  area: 2187.42 },
      {name: '和歌山県', no: 4,area: 4726.12 },
      {name: '香川県', no: 5,  area: 1876.47 },
      {name: '神奈川県', no: 6,area: 2415.84 },
      {name: '岡山県', no: 7,  area: 7113.00 },
      {name: '鹿児島県', no: 8,area: 9187.80 },
      {name: '宮城県', no: 9,  area: 7285.73 },
      {name: '石川県', no: 10, area: 4185.47 },                                
    ],
  }),
  components: {
    VDataTable,
  }
}
</script>
```

Labs の実験的な機能なので、`VDataTable` コンポーネントの明示的な読み込みと追加が必要です（バージョン 3.3.6 現在）。

`v-data-table` についてはボリュームが非常に大きいので、別の記事にしました。

- [DataTable: Vuetify3 の新コンポーネント (labs) を試す](https://qiita.com/mml/items/ae334f79f14469efccf0)

# 複数の画面を切り替える

## 複数の画面をスライドショーのように切り替える v-carousels

いわゆるカルーセルというやつです。

![carousel1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a00b5370-619f-7c01-28e0-04c93eaea30b.gif)

コード：

```App.vue
<template>
<v-container>
  <v-carousel v-model="model">
    <v-carousel-item>
      <v-sheet
        class="bg-red"
        height="400"
        tile
      >
        <h1 class="text-white">Window 1</h1>
      </v-sheet>
    </v-carousel-item>
    <v-carousel-item>
      <v-sheet
        class="bg-blue"
        height="400"
        tile
      >
        <h1 class="text-white">Window 2</h1>
      </v-sheet>
    </v-carousel-item>
    <v-carousel-item>
      <v-sheet
        class="bg-green"
        height="400"
        tile
      >
        <h1 class="text-white">Window 3</h1>
      </v-sheet>
    </v-carousel-item>
  </v-carousel>
  <h1>{{model}}</h1>
</v-container>  
</template>
<script>
export default {
  data: () => ({
    model: 0,
  })
}
</script>
```

`v-for` で作成するほうが楽です。

```App.vue
<template>
<v-container>
  <v-carousel v-model="model">
    <v-carousel-item v-for="item in items" :key="item.color">
      <v-sheet
        :color="item.color"
        height="100%"
        tile
      >
        <h1 class="text-white">Window {{item.num}}</h1>
      </v-sheet>
    </v-carousel-item>
  </v-carousel>
  <h1>{{model}}</h1>
</v-container>  
</template>
<script>
export default {
  data: () => ({
    model: 0,
    items: [
      {
        color: "red",
        num: 1
      },
      {
        color: "blue",
        num: 2
      },
      {
        color: "green",
        num: 3
      },
    ]
  })
}
</script>
```

`v-carousel-item` の中に自作のコンポーネントを入れると、疑似的なページの切り替えができます。

![carousel1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a00b5370-619f-7c01-28e0-04c93eaea30b.gif)

動作自体は全く同じです。

コード：

```App.vue
<template>
<v-container>
  <v-carousel v-model="model">
    <v-carousel-item><HogePageA/></v-carousel-item>
    <v-carousel-item><HogePageB/></v-carousel-item>
    <v-carousel-item><HogePageC/></v-carousel-item>
  </v-carousel>
  <h1>{{model}}</h1>
</v-container>  
</template>
<script>
import HogePageA from './components/HogePageA.vue';
import HogePageB from './components/HogePageB.vue';
import HogePageC from './components/HogePageC.vue';

export default {
  data: () => ({
    model: 0
  }),
  components: {
    HogePageA, 
    HogePageB,
    HogePageC
  }
}
</script>
```

HogePageA.vue

```./components/HogePageA.vue
<template>
    <v-sheet class="bg-red" height="400" tile>
        <h1 class="text-white">Window 1</h1>
    </v-sheet>
</template>
```

HogePageB.vue

```./components/HogePageB.vue
<template>
    <v-sheet class="bg-blue" height="400" tile>
        <h1 class="text-white">Window 2</h1>
    </v-sheet>
</template>
```

HogePageC.vue

```./components/HogePageC.vue
<template>
    <v-sheet class="bg-green" height="400" tile>
        <h1 class="text-white">Window 3</h1>
    </v-sheet>
</template>
```

`v-model` の値をプログラム内で変更すれば、強制的に特定のページを表示させることもできます。

詳しくは公式ドキュメントを参照してください。

- [Carousels](https://next.vuetifyjs.com/en/components/carousels/)

## 複数の画面をタブで切り替える v-tabs

タブを使って画面を切り替えます。

![tabs1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/af307074-302e-85c9-6f1e-ddbe3b704618.gif)

```App.vue
<template>
<v-app>
  <v-container class="pa-2">
    <v-tabs
      v-model="tab"
    >
      <v-tab value="1">Item One</v-tab>
      <v-tab value="2">Item Two</v-tab>
      <v-tab value="3">Item Three</v-tab>
    </v-tabs>

    <v-window v-model="tab">
      <v-window-item value="1">
        <v-sheet
          color="red"
          height="400"
          tile
        >
          <h1 class="text-white">Window 1</h1>
        </v-sheet>
      </v-window-item>

      <v-window-item value="2">
        <v-sheet
          color="blue"
          height="400"
          tile
        >
          <h1 class="text-white">Window 2</h1>
        </v-sheet>
      </v-window-item>

      <v-window-item value="3">
        <v-sheet
          color="green"
          height="400"
          tile
        >
          <h1 class="text-white">Window 3</h1>
        </v-sheet>
      </v-window-item>
    </v-window>
  </v-container>
</v-app>
</template>
<script>
export default {
  data: () => ({
    tab: null,
  }),
}
</script>
```

タブ自体は `v-tabs` で表示します。切り替える画面は `v-window` で作ります。双方の`v-model` に同じ変数を割り当てて置くと、`v-tabs` の切り替えに連動して `v-window 側が切り替わります。

カルーセルと同様に、切り替える画面をコンポーネントとして与えると、疑似的にページ切り替えができます。

![tabs1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/af307074-302e-85c9-6f1e-ddbe3b704618.gif)

動作自体は同じです。

コード：

```App.vue
<template>
  <v-container class="pa-2">
    <v-tabs
      v-model="tab"
    >
      <v-tab value="1">Item One</v-tab>
      <v-tab value="2">Item Two</v-tab>
      <v-tab value="3">Item Three</v-tab>
    </v-tabs>

    <v-window v-model="tab">
      <v-window-item value="1"><HogePageA/></v-window-item>
      <v-window-item value="2"><HogePageB/></v-window-item>
      <v-window-item value="3"><HogePageC/></v-window-item>
    </v-window>
  </v-container>
</template>
<script>
import HogePageA from './components/HogePageA.vue';
import HogePageB from './components/HogePageB.vue';
import HogePageC from './components/HogePageC.vue';

export default {
  data: () => ({
    tab: 0
  }),
  components: {
    HogePageA,
    HogePageB,
    HogePageC,
  }
}
</script>
```

HogePageA.vue

```./components/HogePageA.vue
<template>
    <v-sheet class="bg-red" height="400" tile>
        <h1 class="text-white">Window 1</h1>
    </v-sheet>
</template>
```

HogePageB.vue

```./components/HogePageB.vue
<template>
    <v-sheet class="bg-blue" height="400" tile>
        <h1 class="text-white">Window 2</h1>
    </v-sheet>
</template>
```

HogePageC.vue

```./components/HogePageC.vue
<template>
    <v-sheet class="bg-green" height="400" tile>
        <h1 class="text-white">Window 3</h1>
    </v-sheet>
</template>
```

タブ自体は、単純に値を選ぶことのできるコンポーネントなので、画面の切り替え以外の目的にも使えます。ただ、この用途につかうのであれば、`v-btn-toggle` を使うほうが良いです。

![tabs2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/7c0b33aa-511c-ba0b-2648-14a0b256faff.gif)

コード：

```App.vue
<template>
  <v-container class="pa-2">
    <v-tabs
      v-model="tab"
    >
      <v-tab value="1">Item One</v-tab>
      <v-tab value="2">Item Two</v-tab>
      <v-tab value="3">Item Three</v-tab>
    </v-tabs>
    <h1>{{tab}}</h1>
  </v-container>
</template>
<script>
export default {
  data: () => ({
    tab: 0
  }),
}
</script>
```

タブに色つけるには、`v-app-bar`, `v-sytem-bar`, `v-toolbar`, `v-card` などのスタイルが指定できるコンポーネントに入れる必要があります。`v-tabs` の `color` は、選択されたタブの色として使われます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/28e61759-7fcf-7789-ae05-3167fad1ae79.png)


コード：

```App.vue
<template>
  <v-container class="pa-2">
    <v-toolbar color="primary">
      <v-tabs
        v-model="tab"
        color="secondary"
      >
        <v-tab :value="n" v-for="n in 5">Tab {{n}}</v-tab>
      </v-tabs>
    </v-toolbar>
    <h1>{{tab}}</h1>
  </v-container>
</template>
<script>
export default {
  data: () => ({
    tab: 0
  }),
}
</script>
```


縦方向のタブも作れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/128f5e94-6fab-5a82-2ce4-c8a186e19dfa.png)

コード：

```App.vue
<template>
  <v-container class="pa-2 d-flex">
    
    <v-tabs
      v-model="tab"
      direction="vertical"
      color="primary"
    >
      <v-tab :value="n" v-for="n in 5">Tab {{n}}</v-tab>
    </v-tabs>
    
    <h1>{{tab}}</h1>
    
  </v-container>
</template>
<script>
export default {
  data: () => ({
    tab: 0
  }),
}
</script>
``` 

`v-app-bar` や `v-toolbar` にいれるときに `<template v-slot:extension>` を使うと、デフォルトのバーの下にタブの行を分けて表示できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/fd4c3733-e4a3-cc88-1279-b43bc5a440fb.png)

コード：

```App.vue
<template>
  <v-app>
    <v-app-bar color="primary">
       <v-app-bar-nav-icon></v-app-bar-nav-icon>

      <v-app-bar-title>
        Application
      </v-app-bar-title>

      <v-btn icon="mdi-home">
      </v-btn>
    
      <template v-slot:extension>
        <v-spacer></v-spacer>
        <v-tabs
          v-model="tab"
        >
          <v-tab :value="n" v-for="n in 5" :key="n">Tab {{n}}</v-tab>
        </v-tabs>
        <v-spacer></v-spacer>
      </template>

    </v-app-bar>    
    <v-main>
      <v-container>
        <h1>{{tab}}</h1>
      </v-container>
    </v-main>
  </v-app>
</template>
<script>
export default {
  data: () => ({
    tab: 0
  }),
}
</script>
```

詳細は公式ページを見てください。

- [Tabs](https://next.vuetifyjs.com/en/components/tabs/)

## 大量のデータを一定の個数ごとにページに分けて表示する v-pagination

Google の検索とかで、検索結果が大量にあるときに、表示しきれない部分を次のページ以降に送って、ページ切り替えをして読めるようにするいみたいなコンポーネントです。

`v-pagination` 自体はただのボタンで、ページを送る機能はありません。どのページを表示するかは、選択されたページ番号から自分で作成する必要があります。

最初のページの番号は 1 です。0 を指定すると、どのページ番号も選択されていない状態になります。`length` を超えるページ番号を指定しても、どのページ番号も選択されていない状態になります。

![page1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/be662a88-85db-99b9-a98c-c54787a04609.gif)

コード：

```App.vue
<template>
  <v-container>
    <v-container>
      <v-row>
        <v-col cols="3" v-for="n in 8" :key="n">
          <v-card height="200">
            <v-card-title>Card{{n + 6*(page-1)}}</v-card-title>
          </v-card>
        </v-col>
      </v-row>
    </v-container>
    <v-pagination
      v-model="page"
      length="6"
    ></v-pagination>
  </v-container>
</template>
<script>
export default {
  data () {
    return {
      page: 1,
    }
  },
}
</script>
```

ページ数が多すぎるときに、`total-visible` を指定しておくと、ページ番号を表示する上限を指定できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/0b1ed4c6-bfc5-88a4-094e-b75b4021726d.png)

コード：

```App.vue
<template>
  <v-container>
    <v-container>
      <v-row>
        <v-col cols="3" v-for="n in 8" :key="n">
          <v-card height="200">
            <v-card-title>Card{{n + 6*(page-1)}}</v-card-title>
          </v-card>
        </v-col>
      </v-row>
    </v-container>
    <v-pagination
      v-model="page"
      length="50"
      total-visible="3"
    ></v-pagination>
  </v-container>
</template>
<script>
export default {
  data () {
    return {
      page: 1,
    }
  },
}
</script>
```

`v-toolbar` や `v-card` などスタイルを指定できるコンポーネントに入れると、色を指定できるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/77962f17-a2d4-9587-7232-2fd12ed348a0.png)

コード；

```App.vue
<template>
  <v-container>
    
    <v-container>
      <v-row>
        <v-col cols="3" v-for="n in 8" :key="n">
          <v-card height="200" color="secondary">
            <v-card-title>Card{{n + 6*(page-1)}}</v-card-title>
          </v-card>
        </v-col>
      </v-row>
    </v-container>
    <v-layout>
    <v-toolbar color="primary">
      <v-spacer></v-spacer>
      <v-pagination
        v-model="page"
        length="50"
        total-visible="5"
      ></v-pagination>
      <v-spacer></v-spacer>
    </v-toolbar>
    </v-layout>
  </v-container>
</template>
<script>
export default {
  data () {
    return {
      page: 1,
    }
  },
}
</script>
```

`v-pagination` 自体は、値を選ぶだけの機能のコンポーネントなので、値を選ぶ目的にも使えなくはないです。

最後ページまで飛ぶとか、最初ページまで戻るとか、そういう機能はまだないぽいです（ページ番号を指定して表示を強制的に変更することはできます）。多分、Beta 出なくなるころにはもうちょっと機能が追加されるはず・・・

- [Pagination
](https://next.vuetifyjs.com/en/components/paginations/)

# そのほか便利なやつ

## v-progress-circle / v-progress-linear

ロード中とかにぐるぐる回る表示をしたり、進行状況を表示したりできるコンポーネントです。

![progress1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/f39b514b-f1ec-25e9-b770-083c2b64ad77.gif)

コード：

```App.vue
<template>
  <v-container>
    <v-progress-circular
      :indeterminate="loading"
      color="primary"
    ></v-progress-circular>

    <v-btn @click="loading = !loading" class="ma-3">
      Toggle
    </v-btn>
</v-container>
</template>
<script>
export default {
  data () {
    return {
      loading: false,
    }
  },
}
</script>
```

どのくらい進んでるかの進行度を表示する用途にも使えます。

![progress2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/f2290dc0-f537-c4aa-79a0-9ab8f49b4140.gif)

コード：

```App.vue
<template>
  <v-container>
    <v-progress-circular
      :rotate="360"
      :size="100"
      :width="15"
      :model-value="value"
      color="primary"
    >
      {{ value }}
    </v-progress-circular>

    <v-btn @click="progress" class="ma-3">
      Progress
    </v-btn>
  </v-container>
</template>
<script>
export default {
  data () {
    return {
      value: 0
    }
  },
  methods: {
    progress()
    {
      this.value += 10;
      if ( this.value > 100 ){
        this.value = 0;
      }
    }
  }
}
</script>
```

`v-progress-linear` はバータイプのものです。

![progress4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/fe46f96b-8f2f-c197-2a3e-63624fface24.gif)

コード：

```App.vue
<template>
  <v-container>
    <v-progress-linear
      color="deep-purple accent-4"
      :indeterminate="loading"
      rounded
      height="6"
    ></v-progress-linear>

    <v-btn @click="loading = !loading" class="ma-3">
      Toggle
    </v-btn>

    <v-divider class="my-5"></v-divider>

    <v-progress-linear v-model="value">
    </v-progress-linear>
    {{ value }}

    <v-btn @click="progress" class="ma-3">
      Progress
    </v-btn>
  </v-container>
</template>
<script>
export default {
  data () {
    return {
      value: 0,
      loading: false
    }
  },
  methods: {
    progress()
    {
      this.value += 10;
      if ( this.value > 100 ){
        this.value = 0;
      }
    }
  }
}
</script>
```

- [Progress circular
](https://next.vuetifyjs.com/en/components/progress-circular/)
- [Progress linear
](https://next.vuetifyjs.com/en/components/progress-linear/)

## 仕切りに使える横線 v-divider

そのままです。HTMLの `hr` を美しくした感じです。厚みは `thickness` で指定します。リストとかカードの中の仕切りにも使えます。`inset` を指定すると、カードとかリストいっぱいに広がります。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/0a2ffd3c-6ce4-32ed-daf8-b70f81b34483.png)

```App.vue
<template>
  <v-container>
    <p class="my-3">hogehoge hogehoge</p>
    <v-divider></v-divider>
    <p class="my-3">hogehoge hogehoge</p>
    <v-divider thickness="5"></v-divider>
    <v-card class="my-3" color="secondary">
      <v-card-title>Hoge Card</v-card-title>
      <v-divider inset></v-divider>
      <v-card-text>hogehoge hogehoge</v-card-text>
    </v-card>
    
    <v-list>
      <v-list-item>Hoge1</v-list-item>
      <v-list-item>Hoge2</v-list-item>
      <v-divider></v-divider>
      <v-list-item>Hoge3</v-list-item>
    </v-list>
    
  </v-container>
</template>
```

`bar` 系のコンポーネントで縦方向の仕切りにもできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/4f5ade41-c38c-1080-666d-92cda338240f.png)

コード

```App.vue
<template>
<v-container>
  <v-toolbar>
    <v-toolbar-title>Title</v-toolbar-title>

    <v-divider
      class="mx-4"
      vertical
      thickness="4"
    ></v-divider>

    <v-btn>HOGE1</v-btn>

    <v-divider
      class="mx-4"
      vertical
    ></v-divider>

    <v-btn>HOGE2</v-btn>

  </v-toolbar>
</v-container>
</template>
```

シンプルですが、いろんなところの仕切りとしてかなり使えます。`class="my-3"` とかマージンを指定すると、縦方向の位置の微調整とかにも使えます。なお、水平の線の場合は横方向のマージン指定は無効です。

詳細は下記を見てください。

- [Dividers](https://next.vuetifyjs.com/en/components/dividers/)

## ツールバー v-toolbar

アプリケーションバー (v-app-bar) のように、ボタンとかアイコンとかを横ｎ並べてバーのように表示できます。アプリケーションバーはアプリ内にひとつしか置けませんが、ツールバーはいくつでも置けます。また、`v-layout` も不要です。

下の例のように、ページ内に浮いているカードに着けたりできます。（アプリケーションバーは画面の上に常に張り付く）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/4d0670d6-c867-8d46-4381-28ce4a9b2aa0.png)

コード：

```App.vue
<template>
  <v-card color="blue-lighten-4" width="80%" height="300" class="mx-auto my-3">
    <v-toolbar color="primary">
      <v-app-bar-nav-icon></v-app-bar-nav-icon>
      <v-toolbar-title>v-toolbar-title</v-toolbar-title>
      <v-btn>SignIn</v-btn>
      <v-btn icon="mdi-home"></v-btn>
    </v-toolbar>
  </v-card>
</template>
```

`v-toolbar-title` という要素がありますが、`v-app-bar-title` をつかっても同じ結果になります。将来的には `v-toolbar-title しかダメになるかもしれません。

`v-pagination` や `v-tabs` など、通常では背景色を付けられないコンポーネントに色をつける目的にも使えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/011525ba-1593-caf4-95f6-aefe405b2c80.png)

コード：

```App.vue
<template>
  <v-toolbar color="primary" class="mx-2 my-3">
    <v-spacer></v-spacer>
    <v-pagination length="4">
    </v-pagination>
    <v-spacer></v-spacer>
  </v-toolbar>

  <v-toolbar color="secondary" class="mx-2 my-3">
    <v-spacer></v-spacer>
    <v-tabs>
      <v-tab>HOGE1</v-tab>
      <v-tab>HOGE2</v-tab>
      <v-tab>HOGE3</v-tab>
    </v-tabs>
    <v-spacer></v-spacer>
  </v-toolbar>
</template>
```

`v-footer` にボタンを横方向に配置したいときも、これを使うと楽です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d30942c6-f0bc-e5d8-c333-1c6d6b507267.png)

コード：

```App.vue
<template>
  <v-app>
    <v-main>
      <v-container>
        Main Contents
      </v-container>
    </v-main>
    <v-footer app color="primary">
      <v-toolbar color="primary">
        <v-spacer></v-spacer>
        <v-btn icon="mdi-home"></v-btn>
        <v-btn icon="mdi-file"></v-btn>
        <v-btn icon="mdi-google"></v-btn>
        <v-spacer></v-spacer>
      </v-toolbar>
    </v-footer>
  </v-app>
</template>
```

色を指定するときは、`v-footer` と `v-toolbar` の両方で同じ色を指定するようにします。

詳細は下記を見てください。

- [Toolbars](https://next.vuetifyjs.com/en/components/toolbars/)

## 横方向の空白 v-spacer

横方向に並べられたコンポーネントの間に置くと、その位置に「めいっぱいの」横方向の空白を作ります。同じ行内に複数の `v-spacer` を置くと、`v-spacer ごとに同じだけの横幅が割り当てられます。

コンポーネントを `d-flex` や `v-row` で横に並べているときや、`v-app-bar` や `-v-toolbar` で横に並べているときに、コンポーネント間に空白を作りたいときや。コンポーネントを寄せるときに使います。

機能としては空白を置くだけなんですが、実質的にはコンポーネントを任意の位置に「寄せる」ためのパーツといってもよいでしょう。**非常に汎用性が高い**です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/1a5f0fa6-14e8-bd79-faf5-80ceb24e2ee2.png)

たとえば上の図で、上の二つのような単純な寄せ方なら、`v-spacer` なしでも簡単です。しかし、下の二つのような寄せ方をしようとすると、`v-spacer` なしだと複雑になります。

```App.vue
<template>
<v-container>

  <div class="d-flex justify-end">
    <v-btn>HOGE1</v-btn> 
    <v-btn>HOGE2</v-btn> 
    <v-btn>HOGE3</v-btn> 
  </div>

  <div class="d-flex justify-center my-3">
    <v-btn>HOGE1</v-btn> 
    <v-btn>HOGE2</v-btn> 
    <v-btn>HOGE3</v-btn> 
  </div>

  <div class="d-flex my-3">
    <v-spacer></v-spacer>
    <v-btn>HOGE1</v-btn> 
    <v-spacer></v-spacer>
    <v-btn>HOGE2</v-btn> 
    <v-spacer></v-spacer>
    <v-btn>HOGE3</v-btn> 
    <v-spacer></v-spacer>
  </div>

  <div class="d-flex my-3">
    <v-spacer></v-spacer>
    <v-btn>HOGE1</v-btn> 
    <v-spacer></v-spacer>
    <v-btn>HOGE2</v-btn> 
    <v-btn>HOGE3</v-btn> 
    <v-spacer></v-spacer>
  </div>
</v-container>
</template>
```

`v-spacer` は、`v-radio` ように、普通では `mx-auto` や `d-flex justify-center` がきかないコンポーネントでも寄せられます。上の行は `d-flex justify-center` をつけても中央によりませんが、v-spacer のあるほうは寄ります（中央の行）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/4bec2c18-7f3f-8f53-384c-dfdff78d29a5.png)

コード：

```App.vue
<template>
  <v-container>
    <div class="d-flex justify-center">
        <v-radio-group>
          <div class="d-flex flex-row" >
            <v-radio label="Hoge1" value="1"></v-radio>
            <v-radio label="Hoge2" value="2"></v-radio>
            <v-radio label="Hoge3" value="3"></v-radio>
          </div>
        </v-radio-group>
    </div>

    <div class="d-flex">
      <v-spacer></v-spacer><!-- これを入れると中央に寄せられる -->
        <v-radio-group>
          <div class="d-flex flex-row" >
            <v-radio label="Hoge1" value="1"></v-radio>
            <v-radio label="Hoge2" value="2"></v-radio>
            <v-radio label="Hoge3" value="3"></v-radio>
          </div>
        </v-radio-group>
    </div>

    <div class="d-flex justify-end">
      <div><!-- ダミーの div を入れると右にも寄せられる -->
        <v-radio-group>
          <div class="d-flex flex-row" >
            <v-radio label="Hoge1" value="1"></v-radio>
            <v-radio label="Hoge2" value="2"></v-radio>
            <v-radio label="Hoge3" value="3"></v-radio>
          </div>
        </v-radio-group>
      </div>
    </div>
  </v-container>
</template>
```

これがバグなのか仕様なのかいまいちわかりませんが、`v-radio` は右側に無限のスペースが最初から挿入されているかにように振舞います。`v-spacer` を左側に挿入することで、右側に挿入されたスペースとバランスがとれて、中央によります。

ちなみにこの手のコンポーネントを右に寄せたい場合は、`v-spacer` だけでは無理です。三つ目の例のように、ダミーの div をはさむと寄るようになります。

`v-col` を寄せるときにも `v-spacer` 使えます。むしろ、大抵の場合は `v-spacer` で寄せるほうが楽です。なお、一行に含まれる `cols` の合計値が 12 未満のときでないと、`v-spacer` は無視されます。下の図の一番下の行は `v-spacer` を入れていますが、合計値が 12 になっているため、cols の値による寄せのほうが優先されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/f55ac6a1-a23c-8c93-eaa8-44b5d9c8590f.png)

```App.vue
<template>
  <v-container>
    <v-row>
      <v-spacer></v-spacer>
      <v-col cols="3">
        <v-btn>HOGE1</v-btn>
      </v-col>
      <v-col cols="3">
        <v-btn>HOGE2</v-btn>
      </v-col>
      <v-col cols="3">
        <v-btn>HOGE3</v-btn>
      </v-col>
    </v-row>

    <v-row>
      <v-spacer></v-spacer>
      <v-col cols="3">
        <v-btn>HOGE1</v-btn>
      </v-col>
      <v-col cols="3">
        <v-btn>HOGE2</v-btn>
      </v-col>
      <v-col cols="3">
        <v-btn>HOGE3</v-btn>
      </v-col>
      <v-spacer></v-spacer>
    </v-row>

    <v-row>
      <v-spacer></v-spacer><!-- cols の合計値が12だと無視される -->
      <v-col cols="4">
        <v-btn>HOGE1</v-btn>
      </v-col>
      <v-col cols="4">
        <v-btn>HOGE2</v-btn>
      </v-col>
      <v-col cols="4">
        <v-btn>HOGE3</v-btn>
      </v-col>
      <v-spacer></v-spacer>
    </v-row>
  </v-container>
</template>
```

`v-spacer` は `v-toolbar` や `v-app-bar` でのボタンやアイコンなどの間にスペースを入れるときにもよく使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/8977cda4-400e-9222-2127-d4bace625dff.png)

コード：

```App.vue
<template>
  <v-app>
    <v-app-bar color="primary">
      <v-app-bar-nav-icon></v-app-bar-nav-icon>
      <v-app-bar-title>
        v-space なし
      </v-app-bar-title>
      <v-btn>SignIn</v-btn>
      <v-btn icon="mdi-home"></v-btn>
    </v-app-bar>
  </v-app>
</template>
```

`v-spacer` を入れないと、上のような感じになります。`v-app-bar-title` の右側に自動的にスペースが入って、残りのコンポーネントは右に寄ります。

`v-spacer` を入れると、文字やボタンの位置を左右に動かせます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/20aee201-40e7-99f4-6a6c-c7e2651cf0fd.png)

コード：

```App.vue
  <v-app>
    <v-app-bar color="primary">
      <v-app-bar-nav-icon></v-app-bar-nav-icon>
      <v-spacer></v-spacer>
      <v-app-bar-title>
        v-space あり
      </v-app-bar-title>
      <v-spacer></v-spacer>
      <v-btn>SignIn</v-btn>
      <v-btn icon="mdi-home"></v-btn>
    </v-app-bar>
  </v-app>
</template>
```

`v-app-bar` と `v-toolbar` の中では `justify-center` や `ms-auto` が効かないので、寄せたい場合は `v-spacer` を使う必要があります。

# 結論

Directive については別途まとめる予定です。