🤔

VCombobox VAutocomplete VSelect 変更点(Vuetify 2 〜 Vuetify 3 アップデート)

2024/06/10に公開

Vuetify 3 v-combobox / v-autocomplete / v-selectの変更点

この記事では、Vuetify 3.5.16 でのv-combobox、v-autocomplete、v-selectの変更点をまとめています。この3つのコンポーネントの基本的な機能に大きな差はありませんが、高度なフィルターを使用する場合はv-autocompleteが適しています。個人的には、v-comboboxでほとんどの機能がカバーできると考えています。

公式ドキュメントはこちら:

主な変更点

  1. textからtitleに変更:

    • Vuetify 2ではitem-textだったプロパティが、Vuetify 3ではitem-titleに変更されました。
  2. itemsプロパティのオブジェクト化:

    • itemsプロパティを配列のオブジェクトにする場合、item-titleitem-valueをオブジェクトと関連付ける必要があります。
  3. template slotの変更:

    • template slot itemを使用する場合、セレクトリストの値の取得がitem.nameからitem.raw.nameになりました。
    • template slot itemを利用するとセレクトのイベントが失われ、サジェスト機能も失われます。
  4. クリックイベントの変更:

    • 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 イベントを差し込む必要があります。

Vuetify 3のコードの変更箇所
 <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のスタイルを追加して制御しました。

完成したコードとしては以下になります。

https://nuxt3-vuetify-storybook.pages.dev/?path=/docs/features-dialogcombobox--documentation

https://github.com/redamoon/nuxt3-vuetify-storybook/blob/main/features/DialogCombobox/DialogCombobox.vue

サンプルコード

まとめ

この記事では V-Comboboxを例にコードを紹介しました。
他の V-Select や V-Autocomplete についても同様の変更が必要になります。

item をテンプレート側で対応する場合は、外部処理して加える必要があるようです。
また、移行に伴って確認がとれた部分としてテンプレート側に配置するとサジェスト機能も失われるようです。

この方法は、あくまでも代替案ですが、サジェスト機能までさせるために関数・watchを外部から呼び出すように調整が必要そうです。

いずれは解消されるかもしれませんが、 3.5.16 ではこのような対応が必要になります。
現時点は、UIの変更を検討か別途の対応が必要になります。

株式会社HAMWORKS

Discussion