VCombobox VAutocomplete VSelect 変更点(Vuetify 2 〜 Vuetify 3 アップデート)
Vuetify 3 v-combobox / v-autocomplete / v-selectの変更点
この記事では、Vuetify 3.5.16
でのv-combobox、v-autocomplete、v-selectの変更点をまとめています。この3つのコンポーネントの基本的な機能に大きな差はありませんが、高度なフィルターを使用する場合はv-autocompleteが適しています。個人的には、v-comboboxでほとんどの機能がカバーできると考えています。
公式ドキュメントはこちら:
主な変更点
-
textからtitleに変更:
- Vuetify 2では
item-text
だったプロパティが、Vuetify 3ではitem-title
に変更されました。
- Vuetify 2では
-
itemsプロパティのオブジェクト化:
-
items
プロパティを配列のオブジェクトにする場合、item-title
とitem-value
をオブジェクトと関連付ける必要があります。
-
-
template slotの変更:
-
template slot item
を使用する場合、セレクトリストの値の取得がitem.name
からitem.raw.name
になりました。 -
template slot item
を利用するとセレクトのイベントが失われ、サジェスト機能も失われます。
-
-
クリックイベントの変更:
-
template slot item
を指定するとセレクトする機能が失われるため、代替案として@click
イベントをitemに追加する必要があります。
-
Vuetify 2から3への移行例
Vuetify 2で使用していたv-comboboxのコードをVuetify 3に対応させるための変更例を示します。
Vuetify 2のコード
<template>
<v-app id="app">
<v-container>
<v-combobox
label="ユーザの選択"
:items="items"
:value="value"
item-text="name"
>
<template #prepend-item>
<v-list-item @click="clickPrepend">
<v-list-item-content>
<v-list-item-title> モーダルを表示 </v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-divider class="mt-2 mb-1" />
</template>
<template #selection="{ item }"> {{ item.name }}</template>
<template #item="{ item }">
<div>
<img :src="item.url" alt="" />
<v-list-item-title>{{ item.name }}</v-list-item-title>
</div>
</template>
</v-combobox>
<v-dialog v-model="dialog" width="500">
<v-card>
<v-card-title class="text-h5 grey lighten-2">
モーダルダイアログ
</v-card-title>
<v-card-text> モーダルダイアログの内容 </v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="primary" text @click="dialog = false">
I accept
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-container>
</v-app>
</template>
Vuetify 3のコード
以下のコードでは、itemsのクリックが反応しません。
<template>
<div>
<v-combobox
:items="items"
:model-value="modelValue"
item-title="name"
>
<template #prepend-item>
<v-list-item @click="clickPrepend">
<v-list-item-title> モーダルを表示 </v-list-item-title>
</v-list-item>
<v-divider class="mt-2 mb-1" />
</template>
<template #selection="{ item }">
{{ item.raw.name }}
</template>
<template #item="{ item, index }">
<v-list-item>
<img :src="item.raw.url" alt="">
<v-list-item-title>
{{ item.raw.name }}
</v-list-item-title>
</v-list-item>
</template>
</v-combobox>
<v-dialog v-model="dialog" width="500">
<v-card>
<v-card-title class="text-h5 grey lighten-2">
モーダルダイアログ
</v-card-title>
<v-card-text> モーダルダイアログの内容 </v-card-text>
</v-card>
</v-dialog>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
type Item = {
name: string
url: string
id: number
}
const dialog = ref(false)
const items = ref([
{ name: 'Ken', url: 'https://picsum.photos/60/60', id: 1 },
{ name: 'John', url: 'https://picsum.photos/60/60', id: 2 }
])
const modelValue = ref<Item | null>(null)
const clickPrepend = () => {
dialog.value = true
}
</script>
クリックイベントの修正
クリックイベントと選択されたアイテムに背景をつけるために以下のように @click イベントを差し込む必要があります。
<template>
<div>
<v-combobox
:items="items"
:model-value="modelValue"
item-title="name"
>
<template #prepend-item>
<v-list-item @click="clickPrepend">
<v-list-item-title> モーダルを表示 </v-list-item-title>
</v-list-item>
<v-divider class="mt-2 mb-1" />
</template>
<template #selection="{ item }">
{{ item.raw.name }}
</template>
<template #item="{ item, index }">
- <v-list-item>
+ <v-list-item :class="selectedId === item.raw.id && 'active'" @click="selectedItem(index)">
<img :src="item.raw.url" alt="">
<v-list-item-title>
{{ item.raw.name }}
</v-list-item-title>
</v-list-item>
</template>
</v-combobox>
<v-dialog v-model="dialog" width="500">
<v-card>
<v-card-title class="text-h5 grey lighten-2">
モーダルダイアログ
</v-card-title>
<v-card-text> モーダルダイアログの内容 </v-card-text>
</v-card>
</v-dialog>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
type Item = {
name: string
url: string
id: number
}
const dialog = ref(false)
const items = ref([
{ name: 'Ken', url: 'https://picsum.photos/60/60', id: 1 },
{ name: 'John', url: 'https://picsum.photos/60/60', id: 2 }
])
const modelValue = ref<Item | null>(null)
+ const selectedId = ref<number | null>(null)
const clickPrepend = () => {
dialog.value = true
}
+ const selectedItem = (index: number) => {
+ modelValue.value = items.value[index]
+ selectedId.value = items.value[index].id
+ }
</script>
+ <style scoped>
+ .active {
+ background-color: #CCC;
+ }
+ </style>
この変更により、selectedItem
を用意して、selectedId
と比較してselectionに挿入するように調整します。
また、選択された値の背景も変更する必要があるため、activeのスタイルを追加して制御しました。
完成したコードとしては以下になります。
サンプルコード
まとめ
この記事では V-Comboboxを例にコードを紹介しました。
他の V-Select や V-Autocomplete についても同様の変更が必要になります。
item をテンプレート側で対応する場合は、外部処理して加える必要があるようです。
また、移行に伴って確認がとれた部分としてテンプレート側に配置するとサジェスト機能も失われるようです。
この方法は、あくまでも代替案ですが、サジェスト機能までさせるために関数・watchを外部から呼び出すように調整が必要そうです。
いずれは解消されるかもしれませんが、 3.5.16
ではこのような対応が必要になります。
現時点は、UIの変更を検討か別途の対応が必要になります。
Discussion