Nuxt3プロジェクトにVuetify3を導入してVuetify2と比較してみた

## はじめに
Nuxt3プロジェクトにVuetify3を導入してVuetify2と比較してみました。
Vuetifyは、VueやNuxtプロジェクトにマテリアルデザインのコンポーネントを簡単に統合できるフレームワークです。
本記事は、Nuxt3プロジェクトにVuetify3を導入したい方、Vuetify2からVueyify3に移行を考えている方におすすめです。

## 開発環境
- Windows 11
- Nuxt.js 3.0.0-rc.6
- Vuetify 3.4.0-alpha.0
- npm 8.19.4
- Node.js 16.20.0

## Nuxt3プロジェクトの作成
まず、Nuxt3プロジェクトを作成します。
私は以下の記事の手順で作成しました。

https://qiita.com/tatsuki-tsuchiyama/items/9948020a9a07c5ef20e1


Azure Static Web Appsを使わない場合は、以下の手順で作成してください。

1. Nuxt3プロジェクトを作成します。

    ```
    npx nuxi@latest init nuxt3-app-test
    ```
1. 作成したNuxt3プロジェクトのディレクトリに移動します。
    ```
    cd nuxt3-app-test
    ```
1. 依存関係をインストールします。
    ```
    npm install
    ```
1. 試しに開発モードで起動します。
    ```
    npm run dev -- -o
    ```
以下のような画面が表示されればNuxt3プロジェクトの作成完了です。  
![localhost_3000_ (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/cdc3ef00-c895-cc55-6165-fabda3455272.png)


## Vuetify3の導入
次に、作成したNuxt3プロジェクトにVuetify3を導入します。

1. 以下のコマンドで、Vuetify3の最新版と、スタイルを適用するのに別途必要なmdiとSASSを開発用の依存関係としてインストールします。

    ```
    npm install vuetify@next mdi sass --save-dev
    ```
1. pluginsディレクトリをルートディレクトリ直下に作成し、その中にvuetify.tsファイルを作成します。
    vuetify.tsは以下のようにします。
    ```javascript:vuetify.ts
    import { createVuetify } from "vuetify";
    import * as components from "vuetify/components";
    import * as directives from "vuetify/directives";
    
    export default defineNuxtPlugin((nuxtApp) => {
        const vuetify = createVuetify({
            components,
            directives,
        });
    
        nuxtApp.vueApp.use(vuetify);
    });
    ```
    上記のコードではVuetifyを使用するために必要なモジュールをインストールし、defineNuxtPluginの中でVuetifyのインスタンスを作成してマウントしています。これにより、Vuetifyのコンポーネントやディレクティブが利用できます。

1. nuxt.config.tsを以下のように書き換えます。
    ```javascript:nuxt.config.ts
    export default defineNuxtConfig({
        typescript: {
            shim: false,
        },
        ssr: false,
        css: ["vuetify/lib/styles/main.sass", "mdi/css/materialdesignicons.min.css"],
        build: {
            transpile: ["vuetify"],
        },
        vite: {
            define: {
                "process.env.DEBUG": false,
            },
        },
    });
    ```
    上記の「css:」部分でVuetifyのスタイルを指定し、「build:」部分でビルドプロセスにVuetifyが含まれるように指定しています。

1. Vuetify3のコードを試してみる
    app.vueを以下のように書き換えてください。コードはVuetify3の公式ドキュメントの[こちら](https://vuetifyjs.com/en/components/chips/#colored)のコードを利用しています。

    ```javascript:app.vue
    <template>
      <v-app>
          <div class="text-center">
            <v-chip
              class="ma-2"
            >
              Default
            </v-chip>
    
            <v-chip
              class="ma-2"
              color="primary"
            >
              Primary
            </v-chip>
    
            <v-chip
              class="ma-2"
              color="secondary"
            >
              Secondary
            </v-chip>
    
            <v-chip
              class="ma-2"
              color="red"
              text-color="white"
            >
              Red Chip
            </v-chip>
    
            <v-chip
              class="ma-2"
              color="green"
              text-color="white"
            >
              Green Chip
            </v-chip>
          </div>
      </v-app>
    </template>
    ```

`npm run dev -- -o`を実行すると以下のような画面が表示され、Vuetify3のスタイルが適用されていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/d6f5e56a-481a-bf5b-0b6b-06ecdbd10d63.png)


## Vuetify2との比較
ここからは、Vuetify2とVuetify3の外観とコードの比較結果をまとめています。

### v-btnのサイズ

#### 外観
Vuetify2
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/3abac8da-d5bd-e570-ad2e-af4bda6bb48e.png)

Vuetify3
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/2704fd1a-5172-f6a4-e67d-bf2dac0c4dc8.png)

背景色やフォントが違いますが、サイズの変化具合には、ほとんど違いはありません。

#### コード
|    | Vuetify2  |  Vuetify3  |
|----|----| ----|
|x-small | \<v-btn x-small>Extra small Button\</v-btn>  |   \<v-btn size="x-small">Extra small Button\</v-btn>
| small |\<v-btn small>Small Button\</v-btn>  |   \<v-btn size="small">Small Button\</v-btn>
| normal |\<v-btn>Normal Button\</v-btn>  |   \<v-btn>Normal Button\</v-btn>
| large |\<v-btn large>Large Button\</v-btn>  |   \<v-btn size="large">Large Button\</v-btn>
| x-large |\<v-btn x-large>Extra Large Button\</v-btn>  |   \<v-btn size="x-large">Extra Large Button\</v-btn>

Vuetify2では、単に"small"、"medium"、"large"などのプロパティを追加するだけで設定できましたが、Vuetify3では、sizeプロパティに、"small"、"medium"、"large"などの値を指定する必要があります。


### v-text-fieldのバリエーション

#### 外観
Vuetify2
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/c1dae224-e40c-20d0-4488-5123daad7ca2.png)

Vuetify3
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/f99c363a-6265-b4eb-6e05-72490f2ccd31.png)

「Regular」スタイルには、Vuetify2とVuetify3で異なるデフォルトスタイルが適用されています。Vuetify2では「Underlined」、Vuetify3では「Filled」がデフォルトのスタイルとなるようです。

#### コード
|    | Vuetify2  |  Vuetify3  |
|----|----| ----|
|Regular| \<v-text-field label="Regular">\</v-text-field>  | \<v-text-field label="Regular">\</v-text-field> |
|Solo| \<v-text-field label="Solo" solo>\</v-text-field>  | \<v-text-field label="Solo" variant="solo">\</v-text-field> |
|Filled| \<v-text-field label="Filled" filled>\</v-text-field> | \<v-text-field label="Filled" variant="filled">\</v-text-field>  |
|Outlined| \<v-text-field label="Outlined" outlined>\</v-text-field>  | \<v-text-field label="Outlined" variant="outlined">\</v-text-field> |
|Underlined| \<v-text-field label="Underlined" underlined>\</v-text-field>  | \<v-text-field label="Underlined" variant="underlined">\</v-text-field> |

Vuetify2では、単に"outlined"、"solo"、"underlined"などのプロパティを追加するだけで設定できましたが、Vuetify3では、variantプロパティに、"outlined"、"solo"、"underlined"などの値を指定する必要があります。

### v-text-fieldの高さ

#### 外観
Vuetify2
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/eb2b74c3-16fc-5e85-c630-3e16e2a74afe.png)

Vuetify3
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/6e8dea39-e2b5-0580-d24a-aa07a540a07c.png)

どちらの画像も右側のv-text-fieldが高さを小さくしたものです。Vuetify2とVuetify3で、見た目はほとんど変わりません。Vuetify3の方が若干高さがあるようです。

#### コード
| Vuetify2  |  Vuetify3  |
|----| ----|
| \<v-text-field label="Dense" dense>\</v-text-field>  | \<v-text-field label="Dense" density="compact">\</v-text-field> |

Vuetify2では、denseプロパティを使用しますが、Vuetify3ではdensity="[compact]"のように指定する必要があります。


### v-paginationの形状

#### 外観
Vuetify2
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/26cae331-52c5-775b-d768-6be8c3bb5f29.png)

Vuetify3
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/67fbdfcd-9b10-aaf8-26f4-12793fb71c1c.png)

v-pagination自体に大きな違いが見られます。四角形の場合も円形の場合も、Vuetify3の方がサイズが大きいです。


#### コード
| Vuetify2  |  Vuetify3  |
|----| ----|
| \<v-pagination v-model="[現在のページを管理する変数]" :length="[表示するページネーションの数を格納する変数]" circle>\</v-pagination>  | \<v-pagination v-model="[現在のページを管理する変数]" :length="[表示するページネーションの数を格納する変数]" rounded="circle">\</v-pagination> |

Vuetify2では、circleプロパティを使用しますが、Vuetify3ではroundedプロパティに"circle"の値を指定する必要があります。


### v-tooltip

#### 外観
Vuetify2
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/0aba3735-0004-2ca0-b684-954b98ac6566.png)

Vuetify3
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/f714869a-8f77-26d8-0e78-289fab4b2e07.png)

若干、Vuetify3の方がツールチップの黒色が濃くなっています。表示位置や挙動はほとんど変わりません。

### コード
|    | Vuetify2  |  Vuetify3  |
|----|----| ----|
|左|\<v-tooltip left>\<template v-slot:activator="{ on, attrs }">\<v-btn v-bind="attrs" v-on="on">Left\</v-btn>\</template>\<span>Tooltip</span>\</v-tooltip> | \<v-btn>Start\<v-tooltip activator="parent" location="start">Tooltip\</v-tooltip>\</v-btn> |
|上|\<v-tooltip top>\<template v-slot:activator="{ on, attrs }">\<v-btn v-bind="attrs" v-on="on">Top\</v-btn>\</template>\<span>Tooltip</span>\</v-tooltip> | \<v-btn>Top\<v-tooltip activator="parent" location="top">Tooltip\</v-tooltip>\</v-btn> |
|右|\<v-tooltip right>\<template v-slot:activator="{ on, attrs }">\<v-btn v-bind="attrs" v-on="on">Right\</v-btn>\</template>\<span>Tooltip</span>\</v-tooltip> | \<v-btn>End\<v-tooltip activator="parent" location="end">Tooltip\</v-tooltip>\</v-btn> |
|下|\<v-tooltip bottom>\<template v-slot:activator="{ on, attrs }">\<v-btn v-bind="attrs" v-on="on">Bottom\</v-btn>\</template>\<span>Tooltip</span>\</v-tooltip> | \<v-btn>Bottom\<v-tooltip activator="parent" location="bottom">Tooltip\</v-tooltip>\</v-btn> |


Vuetify2では、left、top、right、bottomプロパティを使用してツールチップの位置を指定します。Vuetify3では、location="top"やlocation="bottom"のようにして値を指定します。また、Vuetify3では、rightを指定する代わりにstart、leftを指定する代わりにendを使用します。

さらに、Vuetify2では、v-tooltipコンポーネントは通常、ホバー対象のコンポーネントの外側に配置されていました。しかし、Vuetify3では、v-tooltipコンポーネントはホバー対象のコンポーネントの内部に配置され、記述量も短縮されています。

### v-radio-groupを横並びにする
#### 外観
Vuetify2
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/681cea4c-4d9a-6ab1-e78b-96fd1c332502.png)

Vuetify3
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/48cd253a-e2f3-ef47-690c-93532b62b1a7.png)

見た目はほとんど変わりませんが、選択されたラジオボタンの色が違います。

### コード
| Vuetify2  |  Vuetify3  |
|----| ----|
| \<v-radio-group row>\<v-radio-group> | \<v-radio-group inline>\<v-radio-group> |

ラジオボタンを横並びにするために、Vuetify2では、rowプロパティを使用しますが、Vuetify3ではinlineプロパティを指定する必要があります。

### テーブルコンポーネント

#### 外観
Vuetify2
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/5dff91f7-ee82-b9f3-f0df-e2f82df32416.png)

Vuetify3
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/32478fb2-ffff-1915-8ee6-5fe23c9bae6f.png)

見た目はほとんど変わらないことが分かります。

### コード
| Vuetify2  |  Vuetify3  |
|----| ----|
| \<v-simple-table>\<v-simple-table> | \<v-table>\<v-table> |

タグの中身は省略していますが、以下のコードを参考にしました。

- [Vuetify2](https://v2.vuetifyjs.com/ja/components/simple-tables/#section-4f7f304465b9)
- [Vuetify3](https://vuetifyjs.com/en/components/tables/#usage)

Vuetify2では、v-simple-tableを使用する必要があります。一方、Vuetify3では、v-simple-tableではなく、v-tableと記述する必要があります。また、この記事を投稿した段階では、Vuetify2で使用されていたv-data-tableはVuetify3には存在せず、別途インポートする必要があるようです。
詳しくは以下を参考にしてください。

https://vuetifyjs.com/en/components/data-tables/basics/


### v-card

#### 外観
Vuetify2
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/7fa3400c-1499-60c1-cc6a-cd7d16ff65ea.png)

Vuetify3
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/0e54ab48-781a-7752-2f78-3005f9eb0813.png)

外観にはほとんど違いがありません。Vuetify3の方が余白が若干狭いようです。

### コード
| Vuetify2  |  Vuetify3  |
|----| ----|
|\<v-card width="400">\<v-card-item>\<v-card-title>This is a title\</v-card-title>\<v-card-subtitle>This is a subtitle\</v-card-subtitle>\</v-card-item>\<v-card-text>This is content\</v-card-text>\</v-card> |\<v-card width="400" title="This is a title" subtitle="This is a subtitle" text="This is content">\</v-card>

Vuetify2では、v-card-title、v-card-subtitle、v-card-textなどのコンポーネントを使用する必要がありました。しかし、Vuetify3では、これらのコンポーネントの代わりに、v-cardタグにtitle、subtitle、textというプロパティを利用できるようになりました。これにより、コードの記述がシンプルになりました。なお、Vuetify2のコードをそのまま貼り付けてもVuetify3で動作します。

<br>
<br>
<br>

他にもVuetify2との違いがあると思われます。最新の情報については、以下をご参照ください。

https://vuetifyjs.com/en/getting-started/upgrade-guide/#styles-and-utility-classes


## おわりに
今回は、Nuxt3プロジェクトにVuetify3を導入して、Vuetify2と比較してみました。
Vuetify2からの変更点は意外と多く、移行は少し手間がかかると思います。
今後はVuetify3が一般的になることが予想されるため、新しいプロジェクトを始める際にはVuetify3をおすすめします。
ぜひ、Vuetify3を導入してマテリアルデザインに基づいたUIを実装してみてください！
最後までお読みいただき、ありがとうございました！

記事に関する質問等ございましたら、コメントもしくは以下のDMにてよろしくお願いします！

https://twitter.com/t___tatsuki

## 参考文献
https://v2.vuetifyjs.com/ja/

https://vuetifyjs.com/en/getting-started/installation/#installation

https://vuetifyjs.com/en/getting-started/upgrade-guide/

https://www.kuzilla.co.jp/blog/230710_vuetify3

https://qiita.com/uraura_hs3/items/1f117b97063b0ae7b940

https://tedate.jp/vue-js/to-use-card-layout-that-support-vue3