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


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

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

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

# 内容

よく使うかどうかは、主観に依存しています。この記事では主に form 関連のコンポーネントについて記述します。

- [v-btn](https://qiita.com/mml/items/ec0a4c63f9d29d8c0203#%E3%83%9C%E3%82%BF%E3%83%B3v-btn) 
- [v-text-field](https://qiita.com/mml/items/ec0a4c63f9d29d8c0203#%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E5%85%A5%E5%8A%9Bv-text-field)
- [v-file-input](https://qiita.com/mml/items/ec0a4c63f9d29d8c0203#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E9%81%B8%E6%8A%9Ev-file-input)
- [v-select](https://qiita.com/mml/items/ec0a4c63f9d29d8c0203#%E3%83%97%E3%83%AB%E3%83%80%E3%82%A6%E3%83%B3%E3%83%A1%E3%83%8B%E3%83%A5%E3%83%BCv-select)
- [v-slider / v-range-slider](https://qiita.com/mml/items/ec0a4c63f9d29d8c0203#%E3%82%B9%E3%83%A9%E3%82%A4%E3%83%80%E3%83%BCv-slider--v-range-slider)
- [v-radio-group / v-radio](https://qiita.com/mml/items/ec0a4c63f9d29d8c0203#%E3%83%A9%E3%82%B8%E3%82%AA%E3%83%9C%E3%82%BF%E3%83%B3v-radio-group--v-radio)
- [v-checkbox](https://qiita.com/mml/items/ec0a4c63f9d29d8c0203#%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%83%9C%E3%83%83%E3%82%AF%E3%82%B9v-checkbox)
- [v-menu](https://qiita.com/mml/items/ec0a4c63f9d29d8c0203#%E3%83%9D%E3%83%83%E3%83%97%E3%82%A2%E3%83%83%E3%83%97%E3%83%A1%E3%83%8B%E3%83%A5%E3%83%BCv-menu)
- [v-tooltip](https://qiita.com/mml/items/ec0a4c63f9d29d8c0203#%E3%83%92%E3%83%B3%E3%83%88%E3%81%AE%E8%A1%A8%E7%A4%BAv-tooltip)
- [v-dialog](https://qiita.com/mml/items/ec0a4c63f9d29d8c0203#%E3%83%80%E3%82%A4%E3%82%A2%E3%83%AD%E3%82%B0v-dialog)
- [v-icon](https://qiita.com/mml/items/ec0a4c63f9d29d8c0203#%E3%82%A2%E3%82%A4%E3%82%B3%E3%83%B3v-icon)
- [v-img](https://qiita.com/mml/items/ec0a4c63f9d29d8c0203#%E7%94%BB%E5%83%8Fv-img)

Vuetify 3.3.6 の使用を前提にしています。動作が異なる場合や、ワーニング等が出るときは package.json のバージョンを確認してください。

詳細については、[Vuetify3 の公式ページ](https://next.vuetifyjs.com/en/)を参照してください。

# 関連記事

- [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-system-bar, v-app-bar, v-navigation-drawer, v-main, v-footer, v-button-navigation があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/bbd35905-1525-3a5f-bbc4-a76a9be21074.png)


コード：

```App.vue
<template>
  <v-app>
    <v-system-bar color="secondary">
      System Bar
    </v-system-bar>

    <v-app-bar color="primary">
      <v-app-bar-title>
        Application Bar
      </v-app-bar-title>
    </v-app-bar>

    <v-navigation-drawer permanent>
      Navigation Drawer
    </v-navigation-drawer>

    <v-main>
      <v-container>
        Main Contents
      </v-container>
    </v-main>

    <v-bottom-navigation>
      Button Navigation
    </v-bottom-navigation>

    <v-footer color="primary" app>
      Footer
    </v-footer>

  </v-app>
</template>
```

- [Vuetify3 beta のレイアウトに関するメモ](https://qiita.com/mml/items/7bdffe5eb5044f861cf1)

上記を参照してください。

# ユーザが操作するパーツ

## ボタン：v-btn

### 基本

マウスでクリックできるボタンです。クリックしたときのアクションは `@click` で指定できます。ボタンのキャプションは、英字を含む場合はすべて大文字に変換されます。

Vuetify2 のときは `v-btn` は `block` 要素だったのが、Vuetify3 stable では `inline` 要素になったようです。そのため、ボタンを複数並べると、デフォルトでは横に並ぶようになりました。

![vuetify3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/829fe83f-f1af-e16c-119d-a7f618e1db21.gif)


コード：

```App.vue
<template>
  <v-btn @click="submit">
    Submit
  </v-btn>
  <v-btn @click="cancel">
    Cancel
  </v-btn>
  {{ message }}
</template>
<script>
export default {
  data: () => ({
    message: ""
  }),
  methods: {
    submit(){
      this.message = "submit";
    },
    cancel(){
      this.message = "cancel";
    }
  }
}
</script>
```

`@click` で指定する関数には、引数も渡せます。

```App.vue
<template>
  <v-btn @click="clickButton('submit')">
    Submit
  </v-btn>
  <v-btn @click="clickButton('cancel')">
    Cancel
  </v-btn>
  {{ message }}
</template>
<script>
export default {
  data: () => ({
    message: ""
  }),
  methods: {
    clickButton(arg){
      this.message = arg;
    }
  }
}
</script>
```

アプリの動作は、上のコードと全く同じになります。

### スタイル（variant）、色、アイコン

variant を使うと、ボタンのスタイルを指定できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/aa63597b-c622-0952-b77c-309099143774.png)

コード：

```App.vue
<template>

  <div class="d-flex justify-space-between ma-2 pa-2">
    <v-btn color="primary">default</v-btn>
    <v-btn color="primary" variant="outlined">アウトライン</v-btn>
    <v-btn color="primary" variant="text">テキスト</v-btn>
    <v-btn color="primary" variant="flat">flat</v-btn>
    <v-btn color="primary" icon="mdi-home"></v-btn>
  </div>

  <div class="d-flex justify-space-between bg-black ma-2 pa-2">
    <v-btn>default</v-btn>
    <v-btn variant="outlined">アウトライン</v-btn>
    <v-btn variant="text">テキスト</v-btn>
    <v-btn variant="flat">flat</v-btn>
    <v-btn icon="mdi-home"></v-btn>
  </div>

  <div class="d-flex justify-space-between bg-black ma-2 pa-2">
    <v-btn color="black">default</v-btn>
    <v-btn color="black" variant="outlined">アウトライン</v-btn>
    <v-btn color="black" variant="text">テキスト</v-btn>
    <v-btn color="black" variant="flat">flat</v-btn>
    <v-btn color="black" icon="mdi-home"></v-btn>
  </div>

</template>
```

色は `color` 属性で指定します。`class` で指定すると、スタイルの整合性が崩れることがあります。スタイルは `variant` で指定します。outlined, flat, text あたりをよく使います。

color の反映のされかたは、`variant` によって違います。ボタンの親要素の背景色も、ボタンの配色に影響します。

アイコンは `icon` 属性で指定します。公式のドキュメントでは、`icon` が指定されているときは、下記のように InnerText があってもテキストが表示されないみたいな掻き方になってますが、実際にはテキストが優先されて表示されます。`icon` 属性を指定するときは、InnerText は空にします。

```.vue
<v-btn icon="mdi-home"> Home </v-btn>
```

なお `icon` 属性を指定すると、自動的にボタンは丸くなります。丸くしたくない場合は、下記のようにします。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/67d515f8-9454-aca4-839d-c3c6794f9b36.png)

コード：

```App.vue
<template>
  <div class="ma-10">
    <v-btn color="black">
      <v-icon>
        mdi-home
      </v-icon>
    </v-btn>
  </div>
</template>
```

### ロード中、無効化

ロード中みたいなボタンも作れます。ボタンの無効化は `disabled` です。

![vuetify3_2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/f8b8cc29-af2a-5763-db57-ab2457efecae.gif)


コード：

```App.vue
<template>
  <v-btn @click="load" :loading="flag" class="ma-2">
    Load
  </v-btn>
  <v-btn @click="cancel" :disabled="!flag" class="ma-2">
    Cancel
  </v-btn>

</template>
<script>
export default {
  data: () => ({
    flag: false
  }),
  methods: {
    load(){
      this.flag = true;
    },
    cancel()
    {
      this.flag = false;
    }
  }
}
</script>
```

ボタンをロード中表示にすると、自動的に無効化されます。

### 別のページに飛ぶボタン

飛ぶ先の URL の指定は `href` 属性を使います。`href` 属性を使わずに `a` 要素を含めた場合、テキストの色はアンカーの色指定に準じるようです。`vue-router` を使用している場合に、サイト内の別のパスに飛ばすには `to` を使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/93c8b8ff-3294-82e0-5b03-52c57e5bc732.png)

コード：

```App.vue
<template>
  <v-btn class="ma-2">
    <a href="https://next.vuetifyjs.com/en/components/buttons/">
      Vuetify3 Button
    </a>
  </v-btn>

  <v-btn class="ma-2"
    href="https://next.vuetifyjs.com/en/components/buttons/">
    Vuetify3 Button
  </v-btn>

  <v-btn class="ma-2"
    to="/about">
    /about
  </v-btn>
</template>
```

なお、`href`, `to` を使うと、何故か block を指定したときのように、ボタンの横幅が画面いっぱいになります。その場合でも max-width を使うか、幅が指定されている親要素に入れることで、横幅の制限はできます。

### その他

他にも、ボタンの角を丸めたり、サイズを指定することもできます。詳しくは下記をどうぞ。

- [Buttons](https://next.vuetifyjs.com/en/components/buttons/)

## テキスト入力：v-text-field

キーボードとかを使って。テキストを入力することのできるコンポーネントです。

### 基本

`v-model` で入力した文字列を取得できます。

![textinput2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/2beeddd1-bc9e-64f7-fe94-25de83631c5c.gif)

コード：

```App.vue
<template>

  <v-container>
  <v-text-field v-model="message">
  </v-text-field>
  {{ message }}
  </v-container>

</template>
<script>
export default {
  data: () => ({
    message: ""
  }),
}
</script>
```

### 入力後に Enter キーを押したら何かする

`v-form` をつかって、昔ながらの書き方をする必要があるようです（多分）。他の方法あるんでしょうか。ページのリロードを防ぐためには、`preventDefault` を書く代わりに `<v-form @submit.prevent="">` とします。

![textinput3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/e93ac170-f0e2-ddf6-fe13-4e34ee5d1d59.gif)

コード：

```App.vue
<template>
  <v-container>
    <v-form action="#" @submit.prevent="pushEnter">
      <v-text-field v-model="inputText">
      </v-text-field>
    </v-form>
    {{ message }}
  </v-container>

</template>
<script>
export default {
  data: () => ({
    message: "",
    inputText: ""
  }),
  methods:{
    pushEnter()
    {
      this.message = this.inputText;
      this.inputText = "";
    }
  }
}
</script>
```


### いろいろなスタイル

テキストを入力する前の状態：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/200c182d-079d-993b-81a5-760a99f47aa3.png)

テキストを入力した後の状態：

![textinput1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/531c15e5-53b4-a6ee-1de1-ea3d642fe253.gif)

コード：

```App.vue
<template>
  <v-container class="pa-2" >
    <v-text-field
    ></v-text-field>

    <v-text-field
        label="デフォルトのスタイル"
        placeholder="「ここに何か入力しろ」とか書ける"
    ></v-text-field>

    <v-text-field
        label="下線だけのシンプルスタイル"
        variant="underlined"
        placeholder="clearableを付けると、右にXボタンが出るようになる。"
        clearable
    ></v-text-field>

    <v-text-field
        label="枠囲みのスタイル"
        variant="outlined"
        placeholder="counterを付けると文字数を表示する（あくまで数えるだけ）"
        counter="20"
    ></v-text-field>

    <v-text-field
        label="コンパクトサイズ"
        hide-details="auto"
        placeholder="詳細表示のスペースがなくなって、縦幅が小さくなる。"
    ></v-text-field>
    <v-text-field
        label="デフォルト"
        placeholder="デフォルトだと下に少しスペースがあいている。"
    ></v-text-field>

    <v-sheet width="50%">
    <v-text-field
        label="サイズ制限"
        placeholder="幅が指定された親要素に入れて制限するか、v-col などを使う。"
    ></v-text-field>
    </v-sheet>
  </v-container>
</template>
```

横幅は、親要素いっぱいに広がります。横幅を制限したいときは、親要素の幅を指定します。

### 色の指定

基本的に、自由に指定できません。テキストや下線などの色は、`v-text-field` 指定しても反映されません。親要素の色から、自動的に、`v-text-field` の配色が決まるようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/aa8c5e22-fe15-b6e7-9062-f25c100233fd.png)

コード：

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

    <v-container class="d-flex flex-row"> 
      <v-sheet class="bg-black ma-2" width="50%">
        <v-text-field
          label="背景が black の場合"
        ></v-text-field>
      </v-sheet>
      <v-sheet class="bg-grey ma-2" width="50%">
        <v-text-field
          label="背景が gray の場合"
        ></v-text-field>
      </v-sheet>
    </v-container>

    <v-container class="d-flex flex-row"> 
      <v-sheet class="bg-red ma-2" width="50%">
        <v-text-field
          label="背景が red の場合"
        ></v-text-field>
      </v-sheet>
      <v-sheet class="bg-blue ma-2" width="50%">
        <v-text-field
          label="背景が blue の場合"
        ></v-text-field>
      </v-sheet>
    </v-container>

    <v-container class="d-flex flex-row"> 
      <v-sheet class="bg-red-darken-4 ma-2" width="50%">
        <v-text-field
          label="背景が red-darken-4 の場合"
        ></v-text-field>
      </v-sheet>
      <v-sheet class="bg-blue-darken-4 ma-2" width="50%">
        <v-text-field
          label="背景が blue-darken-4 の場合"
        ></v-text-field>
      </v-sheet>
    </v-container>    

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

`v-text-field` はイベント周りの実装が全然進んでない感じなので、beta9 の時点ではかなり使いづらいです。

## ファイル選択：v-file-input

ローカルファイルを選択するためのコンポーネントです。

### JSONファイルを読み込んで表示する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/417410aa-3fbb-4963-a986-7c1f319d2fd5.png)

下記のコードで、JSONファイルを読み込ませてページ内に表示します。テキストファイルは、だいたい同じ方法で読めます。バイナリを読ませるときは `readFile` を使うと `UInt8Array` として読めます（多分）。

```App.vue
<template>
  <v-file-input
      v-model="files"
      accept="application/json"
      @update:modelValue="readFile"
  ></v-file-input>
  <pre>
  {{ data }}
  </pre>
</template>
<script>
export default {
  data: () => ({
    files: [],
    fileReader: null,
    data: ""
  }),
  mounted(){
    this.fileReader = new FileReader();
    this.fileReader.onload = (event) => {
        this.data = JSON.parse(event.target.result);
    }
  },
  methods:{
    readFile()
    {
      if ( this.files.length == 0 ) return;
      this.fileReader.readAsText(this.files[0]);
    }
  }
}
</script>
```

ポイントは、`v-model` に与える変数を、あらかじめ `[]` で初期化しておくことです。バージョン２のときは、ここは配列でなくてもよかったのですが、３からは必ず配列でないとダメになりました。

ファイルを選択したときのイベントは `@update:modelValue` です。`@change` とか `@update` では動きません。

### 画像を読み込んで表示させる

`v-file-input` で選んだローカルファイルを canvas に表示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b94149d3-26ea-76ce-c562-16f830b14da1.png)

```App.vue
<template>
  <v-file-input
      v-model="files"
      accept="image/*"
      @update:modelValue="readFile"
      label="画像ファイルを選択してください"
  ></v-file-input>
  <canvas id="main" width="640" height="480"></canvas>
</template>
<script>
export default {
  data: () => ({
    files: [],
  }),
  methods:{
    drawImage(src)
    {
      const canvas = document.getElementById('main');
      const ctx = canvas.getContext('2d');
      ctx.clearRect(0, 0, 640, 480 );
      const image = new Image();
      image.src = src;
      image.onload = () => {
        ctx.drawImage(image, 0, 0 );
      };
    },
    readFile()
    {
      if ( this.files.length == 0 ) return;
      const fileReader = new FileReader();
      fileReader.onload = () => {
        this.drawImage(fileReader.result);
      };
      fileReader.readAsDataURL(this.files[0]);
    }
  }
}
</script>
```

audio, video なども同じような方法でいけます。

スタイルは、あまり選択肢がないです。現状、TIPSを表示するとか、複数ファイル選択可能にするくらいです。

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

- [File inputs](https://next.vuetifyjs.com/en/components/file-inputs/)

## プルダウンメニュー：v-select

クリックすると下側（もしくは上側）に項目の一覧が表示されて、そこからひとつの要素を選択できるコンポーネントです。メニューの開く方向は、コンポーネントが画面上のどこにあるかで勝手に決まります（多分）。

![select1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/613827b1-64a1-0927-c7a2-541eca91f926.gif)

コード：

```App.vue
<template>
  <v-container>
    <v-select
      :items="['hoge1','hoge2','hoge3','hoge4']"
      label="label"
      class="ma-2"
      v-model="select"
    ></v-select>
  </v-container>
</template>
<script>
export default {
  data: () => ({
    select: null,
  }),
}
</script>
```

コンソールに `reactivity.esm-bundler.js:1092 toRefs() expects a reactive object but received a plain one.` というワーニングが出る場合は、Vuetify のバージョンが古いかもしれません。package.json を見てバージョンが `3.0.0-beta.9` 以上かどうかを確認してください。

- [Selects](https://next.vuetifyjs.com/en/components/selects/)

## スライダー：v-slider / v-range-slider

0から100までの間の値を、スライダーで選ぶことができるコンポーネントです。デフォルトでは線が白になってます。

![slider1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/fae31b2a-8160-5cee-07d4-a4f137be2cb5.gif)

コード：

```App.vue
<template>
  <v-container>
    <v-slider
      v-model="data"
      color="black"
      label="default"
    ></v-slider>
    {{ data }}
  </v-container>
</template>
<script>
export default {
  data: () => ({
    data: null,
  }),
}
</script>
```

初期値を与えたり、連続値でなく飛び飛びの値にすることもできます。

![slider2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/eae36ccf-4185-8144-8000-0af155144393.gif)

コード：

```App.vue
<template>
  <v-container>
    <v-slider
      color="black"
      v-model="data"
      :min="0"
      :max="1"
      :step="0.1"
      thumb-label
    ></v-slider>
    {{ data }}
  </v-container>
</template>
<script>
export default {
  data: () => ({
    data: 0,
  }),
}
</script>
```

詳しくは下記を参照してください。

- [Sliders](https://next.vuetifyjs.com/en/components/sliders/)

## ラジオボタン：v-radio-group / v-radio

いくつかの選択肢からひとつを選んでチェックを入れるコンポーネントです。

![radio1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/ef1a6179-c659-d3df-4ed2-6687bfb7a791.gif)

```App.vue
<template>
  <v-container>
    <v-radio-group v-model="radioGroup">
      <v-radio label="Hoge1" value="1"></v-radio>
      <v-radio label="Hoge2" value="2"></v-radio>
      <v-radio label="Hoge3" value="3"></v-radio>
    </v-radio-group>    
    <h1>{{ radioGroup }}</h1>
  </v-container>
</template>
<script>
export default {
  data () {
    return {
      radioGroup: "3"
    }
  },
}
</script>
```

`<v-radio-group>` の中にある `<v-radio>` が選択対象になります。`v-radio` は `value` で区別されます。`value` が設定されていないと、チェックすることができません。同じ `value` を持つ `v-radio` を配置すると、チェックしたときに、同じ `value` を持つ `v-radio` がすべて同時に選択された状態になります。

なお、 `<v-radio>` は `<v-radio-group>` の直下の子要素でなくても構いません。

たとえば横に並べたいときは、以下のようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/45db453f-9243-0b0d-f0a1-9bac01574ac7.png)


```App.vue
<template>
  <v-container>
    <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>
  </v-container>
</template>
```

`v-row`, `v-col` で寄せることもできます。

`d-flex` で寄せる場合、`v-radio-group` はダミーの `v-sheet` なり `div` などで囲わないと中央寄せにはならないようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/dc881aef-5fcf-13ee-bc07-7af2066e2e2e.png)

```App.vue
<template>
  <v-container>
    <div class="d-flex justify-center">
      <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>
```

このように、ダミーの div をひとつ挟まないと、中央に寄せることができません。

```App.vue
<template>
  <v-container>
    <v-row>
      <v-col class="d-flex justify-center">
        <div><!-- これがないと中央によらない -->
        <v-radio-group>
          <v-row>
            <v-col><v-radio label="Hoge1" value="1"></v-radio></v-col>
            <v-col><v-radio label="Hoge2" value="2"></v-radio></v-col>
            <v-col><v-radio label="Hoge3" value="3"></v-radio></v-col>
          </v-row>
        </v-radio-group>
        </div>
      </v-col>
    </v-row>
  </v-container>
</template>
```

`v-col` で寄せるときも、同様にダミーの `div` が必要のようです。（微妙に寄り方が違います）

`div` を入れるより `v-spacer` を入れるほうが、若干（コードが）すっきりする気がします。詳しくは`[Vuetify3 beta でよく使うコンポーネントのメモ（２）](https://qiita.com/mml/items/16030c4404b4a814956b)の記事の「横方向の空白」の項目を見てください。

- [Radio buttons](https://next.vuetifyjs.com/en/components/radio-buttons/)

## チェックボックス：v-checkbox

個別の項目について、チェックを入れたり外したりできるコンポーネントです。`value` か `v-model` のどっちかが欠けていると、チェックを入れることができません。

![sample2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/5c32ed50-e1de-e60b-e501-1899bc03c205.gif)

チェックした値は `v-model` で取得できます。チェックを入れると、`v-model` で指定した配列の中に `value` で指定した文字列が追加されます。`color` で指定した色は、チェックを入れるところにだけ反映されるようです。

```App.vue
<template>
  <v-container>
    <v-checkbox v-model="selected" value="1" label="Hoge1">
    </v-checkbox>
    <v-checkbox v-model="selected" value="2" label="Hoge2" color="red">
    </v-checkbox>
    <v-checkbox v-model="selected" value="3" label="Hoge3" color="blue">
    </v-checkbox>
    <h1>{{selected}}</h1>
  </v-container>
</template>
<script>
export default {
  data: () => ({
    selected: []
  }),
}
</script>
```

他の要素と同様に、デフォルトでは縦に並びます。横に並べたければ、`d-flex` を使うか `v-col` を使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/25bb6218-0757-c120-9fc1-0742b0fbc494.png)

コード：

```App.vue
<template>
  <v-container>
    <v-row>
      <v-col>
        <v-checkbox v-model="selected" value="1" label="Hoge1">
        </v-checkbox>
      </v-col>
      <v-col>
        <v-checkbox v-model="selected" value="2" label="Hoge2" color="red">
        </v-checkbox>
      </v-col>
      <v-col>
        <v-checkbox v-model="selected" value="3" label="Hoge3" color="blue">
        </v-checkbox>
      </v-col>
    </v-row>
    <h1>{{selected}}</h1>
  </v-container>
</template>
<script>
export default {
  data: () => ({
    selected: []
  }),
}
</script>
```

`v-toolbar` を使う方法もあります。`v-toolbar` を使うと背景色も設定できます（`v-checkbox` に `class="bg-black"` などと直接設定しても、背景色は反映されない）。

しかし、この方法できれいに並べるのはまあまあ難易度高いです。`v-checkbox` は下側に謎の空白があって、そのせいで普通に配置するとやたら上に寄った感じになります。マージンやパディングを設定して、`density="compact"` とかやって、ようやく下の図くらいになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/7ace7d05-c0cf-fdcc-6a07-b5a724c3e753.png)

コード：

```App.vue
<template>
<v-toolbar class="pt-4 mt-3" density="compact" color="blue-darken-2">
  <v-spacer></v-spacer>
  <v-checkbox 
    label="hoge1" value="1" v-model="selections" density="compact">
  </v-checkbox>
  <v-checkbox 
    label="hoge2" value="2" v-model="selections" density="compact">
  </v-checkbox>
  <v-checkbox 
    label="hoge3" value="3" v-model="selections" density="compact">
  </v-checkbox>
</v-toolbar>
</template>
<script>
export default {
  data: () => (
  {
    selections: []
  }),
}
</script>
```

ラベルは右側にしか配置できないようです。左に配置したい場合は、テキスト無しの `v-checkbox` と文字列を横に並べるみたいなことをする必要があります。

- [Checkboxes](https://next.vuetifyjs.com/en/components/checkboxes/)

## ポップアップメニュー；v-menu

ボタンを押してメニューを表示させることができるコンポーネントです。プルダウンメニューと似てますが、プルダウンメニューが項目から一つを選択する用途に使われるのに対して、こちらは選択した後に、何らかのアクションを実行する用途に使われることが多い気がします。

![vuetify11.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/29bc4749-62ba-c25b-baec-42501ac31a85.gif)

コード：

```App.vue
<template>
  <v-container>
   <v-btn
      class="ma-3"
      color="primary"
    >
      メニューを表示するボタン

      <v-menu activator="parent">
        <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>
      </v-menu>
    </v-btn>

    <h1>{{ message }}</h1>
  </v-container>
</template>
<script>
export default {
  data: () => ({
    message: null
  }),
  methods: {
    clickItem(val){
      this.message = val.id;
    }
  }
}
</script>
```

`<v-menu>` 自体はポップアップする枠だけを作る要素なので、中身は `<v-list>` などで別に作る必要があります。

メニューを表示させるボタンとメニューを、親子関係なしに作ることもできます。

![vuetify12.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/9af23339-3523-dbe9-14a2-2f8ff47cc512.gif)

コード：

```App.vue
<template>
 <v-container>
    <v-btn
      id="menu-activator"
      color="secondary"
    >
      ボタンとメニューを別々に配置
    </v-btn>

    <v-menu activator="#menu-activator">
      <v-list>
        <v-list-item value="1">HOGE1</v-list-item>
        <v-list-item value="2">HOGE2</v-list-item>
      </v-list>
    </v-menu>
  </v-container>
</template>
```

ボタンに `id` を設定し、その `id` を `v-menu` 側の `activator` で指定します。

ボタンをクリックしなくても、マウスカーソルが乗っただけでメニューを出すこともできます。

![vuetify13.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/76b3237f-8334-ffdb-18f7-94732f23c0c7.gif)

```App.vue
<template>
  <v-container>
    <v-btn
      color="primary"
      id="menu-popup"
    >
      メニューボタン 
    </v-btn>
    <v-menu
      open-on-hover
      activator="#menu-popup"
    >
      <v-list>
        <v-list-item value="1">HOGE1</v-list-item>
        <v-list-item value="2">HOGE2</v-list-item>
      </v-list>
    </v-menu>
  </v-container>
</template>
```

`v-menu` に `open-on-hover` 属性を追加すると、マウスカーソルが乗っただけでメニューがでるようになります。

- [Menus](https://next.vuetifyjs.com/en/components/menus/)

# ポップアップ、ヒント表示など

## ダイアログ：v-dialog

ボタンなどを押すと、画面上にポップアップするダイアログを表示します。メニューと動作的にはよく似ています。メニューに比べると、ダイアログはポップアップのオンオフ制御を、コード内からできるので、その分だけ制御の自由度が高くなっています。たとえばメニューは、アクションを実行すると勝手に閉じてしまいますが、ダイアログはボタンを押してもとじないような制御もできます。

![vuetify14.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/13506cf2-f2de-de8a-29f0-f10afba85a93.gif)

コード：

```App.vue

<template>
  <v-container >
    <v-btn
      color="primary"
    >
      Open Dialog
      <v-dialog
        v-model="dialog"
        activator="parent"
      >
        <v-sheet>
          <v-sheet class="my-2 mx-5">
            <h2>Dialog!</h2>

            <p class="my-4">
              dialog dialog dialog dialog dialog dialog
            </p>

            <v-btn color="primary" block @click="dialog = false">Close</v-btn>
          </v-sheet>
        </v-sheet>
      </v-dialog>
    </v-btn>
  </v-container>
</template>
<script>
export default {
  data () {
    return {
      dialog: false,
    }
  },
}
</script>
```

ダイアログを開くコンポーネント `v-btn` の子要素として `v-dialog` を配置し、`activator="parent"` と指定することで、ボタンを押すと開くダイアログを作ることができます。ダイアログの表示は `v-model` で制御します。true にすると表示され、false とすると非表示になります。 ダイアログの中には `v-sheet` や `v-card` などを置いてから、その中にダイアログの中に要素を配置します。

ボタンとダイアログを別々に作ることもできます。

![vuetify15.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/93c78c5a-2b5b-a1ac-34dd-3168e8f5ef89.gif)


先の例とは、ダイアログが表示されるときのアニメーション（トランジション）が少し変わります。

```App.vue
<template>
  <v-container >
    <v-btn
      @click="dialog = true"
      color="primary"
    >
      Open Dialog
    </v-btn>
      
    <v-dialog
      v-model="dialog"
    >
      <v-sheet>
        <v-sheet class="my-2 mx-5">
          <h2>Dialog!</h2>

          <p class="my-4">
            dialog dialog dialog dialog dialog dialog
          </p>

          <v-btn color="primary" block @click="dialog = false">Close</v-btn>
        </v-sheet>
      </v-sheet>
    </v-dialog>

  </v-container>
</template>
<script>
export default {
  data () {
    return {
      dialog: false,
    }
  },
}
</script>
```

メニューと同様に、ダイアログを開くボタンに `id` を付けて、`v-dialog` の `activator' でその `id` を指定することで、開くようにすることもできます。動作としては、上のコードと同じになります。

```App.vue
<template>
  <v-container>
    <v-btn
      id="menu-popup"
      color="primary"
    >
      Open Dialog
    </v-btn>
      
    <v-dialog
      v-model="dialog"
      activator="#menu-popup"
    >
      <v-sheet>
        <v-sheet class="my-2 mx-5">
          <h2>Dialog!</h2>

          <p class="my-4">
            dialog dialog dialog dialog dialog dialog
          </p>

          <v-btn color="primary" block @click="dialog = false">Close</v-btn>
        </v-sheet>
      </v-sheet>
    </v-dialog>

  </v-container>
</template>
<script>
export default {
  data () {
    return {
      dialog: false,
    }
  },
}
</script>
```

複数のボタンを配置して、ボタンによって動作を変えることもできます。

![vuetify16.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/1a7f0951-985f-d5ce-6efa-98ef53adabda.gif)

下記のコードでは OK を押すと数字を１増やし、Cancelを押したときは数字を増やしません。

```App.vue
<template>
  <v-container>
    <v-btn
      @click="dialog = true"
      color="primary"
    >
      Open Dialog
    </v-btn>

    <h2>
      {{counter}}
    </h2>
      
    <v-dialog
      v-model="dialog"
    >
      <v-sheet>
        <v-sheet class="my-2 mx-5">
          <h2>Dialog!</h2>

          <p class="my-4">
            数字を１増やします。数字を１増やします。
          </p>

          <div class="d-flex justify-end my-2">
            <v-btn class="mx-2" color="primary" @click="click(true)">OK</v-btn>
            <v-btn class="mx-2" color="error" @click="click(false)">Cancel</v-btn>
          </div>
        </v-sheet>
      </v-sheet>
    </v-dialog>

  </v-container>
</template>
<script>
export default {
  data () {
    return {
      dialog: false,
      counter: 0,
    }
  },
  methods: {
    click(flag){
      if ( flag ){
        this.counter ++;
      }
      this.dialog = false;
    }
  }
}
</script>
```

ダイアログの詳細については下記を参照してください。

- [Dialogs](https://next.vuetifyjs.com/en/components/dialogs/)

## ヒントの表示：v-tooltip

ボタンなどのコンポーネントにマウスを置くと、そのコンポーネントのヒントが表示されます。

![vuetify17.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b38eaf75-ca44-55a1-ae5d-2128625cc00a.gif)

コード：

```App.vue
<template>
  <v-container class="d-flex justify-center">
    <v-btn color="primary" class="mx-3">
      ボタン
      <v-tooltip
        activator="parent"
        location="start"
      >ヒントの表示(左)</v-tooltip>
    </v-btn>

    <v-btn color="primary"  class="mx-3">
      ボタン
      <v-tooltip
        activator="parent"
        location="bottom"
      >ヒントの表示(下)</v-tooltip>
    </v-btn>
  </v-container>
</template>
```

ツールチップを表示させたいコンポーネントが親になるように、`v-tooltop` を配置して、`activator="parent"` を指定します。

この方法でツールチップを配置できるのは、現状 `v-btn`, `div`, `span`, `p` あたりのようです。

![vuetify18.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/06de53e7-be60-fb83-284d-b157ea1e46b8.gif)

コード：

```App.vue
<template>
  <v-container class="d-flex justify-center">
    <div class="mx-2">
      文章のどこを触ってもヒントが出ます。      
      <v-tooltip
        activator="parent"
        location="bottom"
      >
        ヒントの表示(上)
      </v-tooltip>
    </div>

    <div class="mx-2">
      文章の途中でも
      <span class="text-red">
        ヒントを出す  
        <v-tooltip
          activator="parent"
          location="bottom"
        >
          ヒントの表示(左)
        </v-tooltip>
      </span>
      ことができます。
    </div>
  </v-container>
</template>
```

詳細は下記をどうぞ。

- [Tooltips](https://next.vuetifyjs.com/en/components/tooltips/)

# 画像とアイコン

## アイコン：v-icon

Material Design Icon は、Vuetify3 をインストールすれば使うことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/23b22f38-e69c-c745-7462-774df05895f5.png)

コードは、下記のどちらの方法でも同じ結果になります。

```App.vue
<template>
  <v-container>
    <v-icon>
      mdi-home
    </v-icon>

    <v-icon icon="mdi-home"></v-icon>
  </v-container>
</template>
```

アイコンについては、下記のアイコンの項目を見てください。

- [Vuetify3 のレイアウトに関するメモ](https://qiita.com/mml/items/7bdffe5eb5044f861cf1)

公式のドキュメントは下記です。

- [Icons](https://next.vuetifyjs.com/en/components/icons/)

## 画像：v-img

`img` に比べると、表示のオプションが少しリッチになっています。画像のサイズを明示的に指定しない場合、画面のサイズや親コンポーネントのサイズにあわせて、自動的に画面内に入るようにリサイズされます。

![img1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/996aefc9-7f78-f402-3336-752b0d08012f.gif)

コード：

```App.vue
<template>
  <v-container>
    <v-img src="https://cdn.vuetifyjs.com/images/parallax/material.jpg">
    </v-img>

    <div class="d-flex my-4">
    <v-img src="/images/logo.png"></v-img>
    <v-img :src="logoPNG"></v-img>
    <v-img :src="logoSVG"></v-img>
    </div>
  </v-container>
</template>
<script>
import image1 from './assets/logo.png';
import image2 from './assets/logo.svg';

export default {
  data: () => ({
    logoPNG: image1,
    logoSVG: image2,
  })
}
</script>
```

ただし、`img` タグとは微妙に挙動が違うので、用途によっては `img` を使ったほうがいいこともあります。

`src` を `http` や `https` で指定するときは特に問題はないです。ローカルのファイルを指定するときは、下記のいずれかの方法を使う必要があります (Vue.js + npm/yarn で開発している場合）。

- `/public` 以下に画像ファイルを置いて、絶対パスで指定する。
- `/src/assets` 以下に画像ファイルを置いて、相対パスで `import` を使って読み込む。

上のソースコードでは、画像ファイルを以下のパスに置いてます。`App.vue` は `/src/App.vue` に置かれているという前提です。

- `/public/images/logo.png`
- `/src/assets/logo.png`
- `/src/assets/logo.svg`

`img` で表示する場合は `assets` に置く場合でも、`import` することなく、下記のコードでいけます。

ただし、下の画像のように `v-img` のように自動ではリサイズされません。style などで明示的に相対的なサイズを指定するなどして、画面内におさまるようにコーディングする必要があります。

![img2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/f3662afc-f71b-2e83-0685-7c8e8d16ae44.gif)

コード：

```App.vue
<template>
  <v-container>
    <img width="450" src="https://cdn.vuetifyjs.com/images/parallax/material.jpg"/>

    <div class="d-flex my-4">
    <img height="150" src="/images/logo.png"/>
    <img height="150" src="./assets/logo.png"/>
    <img height="150" src="./assets/logo.svg"/>
    </div>
  </v-container>
</template>
```

`v-img` は、ロード中にぐるぐるを表示させたり、`src` の URL にアクセスできないときに取り合えず表示させるデフォルトの画像を設定したり、リサイズ時のアスペクト比を固定する、しないを選択したり、などといったことができます。

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

- [Images](https://next.vuetifyjs.com/en/components/images/)


# 続き

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