Селекты v-select

v-select — один из базовых компонентов библиотеки Vuetify, предназначенный для выбора значения из выпадающего списка. Компонент реализует расширенный вариант HTML-элемента <select>, добавляя возможности поиска, кастомного отображения элементов, множественного выбора, работы с объектами и интеграции с формами.

В основе v-select лежит компонент v-text-field, который дополняется меню (v-menu) и списком (v-list). Благодаря этому он поддерживает все стандартные свойства текстовых полей Vuetify: стилизацию, валидацию, состояния загрузки и взаимодействие с формами.


Базовое использование

Минимальный пример v-select включает два обязательных параметра:

  • v-model — текущее выбранное значение
  • items — массив элементов списка
<template>
  <v-select
    v-model="selected"
    :items="items"
    label="Выберите элемент"
  ></v-select>
</template>

<script>
export default {
  data () {
    return {
      selected: null,
      items: ['JavaScript', 'TypeScript', 'Vue']
    }
  }
}
</script>

В этом примере:

  • список формируется из массива строк
  • selected содержит выбранное значение
  • label отображает подпись поля

Структура данных элементов

items может содержать не только строки, но и объекты. Это наиболее распространённый вариант при работе с API.

Стандартная структура объекта:

{
  title: 'JavaScript',
  value: 'js'
}

Пример:

<v-select
  v-model="selected"
  :items="items"
  label="Язык программирования"
></v-select>
data () {
  return {
    selected: null,
    items: [
      { title: 'JavaScript', value: 'js' },
      { title: 'TypeScript', value: 'ts' },
      { title: 'Python', value: 'py' }
    ]
  }
}

По умолчанию:

  • title — отображаемый текст
  • value — значение, записываемое в v-model

Настройка названий полей

Если структура объектов отличается от стандартной, используются свойства:

  • item-title
  • item-value
<v-select
  v-model="selected"
  :items="users"
  item-title="name"
  item-value="id"
  label="Пользователь"
></v-select>
users: [
  { id: 1, name: 'Алексей' },
  { id: 2, name: 'Мария' }
]

В этом случае:

  • в списке отображается name
  • в v-model сохраняется id

Множественный выбор

Для выбора нескольких значений используется свойство multiple.

<v-select
  v-model="selected"
  :items="items"
  multiple
  label="Технологии"
></v-select>

Теперь v-model хранит массив:

selected: ['JavaScript', 'Vue']

Отображение выбранных элементов

При множественном выборе выбранные элементы отображаются в виде чипов (chips).

<v-select
  v-model="selected"
  :items="items"
  multiple
  chips
></v-select>

Дополнительные параметры:

Свойство Назначение
chips отображение значений как чипов
closable-chips возможность удалить элемент
hide-selected скрытие выбранных элементов в списке

Пример:

<v-select
  v-model="selected"
  :items="items"
  multiple
  chips
  closable-chips
  hide-selected
></v-select>

Поиск внутри списка

v-select поддерживает фильтрацию элементов.

Для включения поиска используется v-autocomplete, однако v-select также может фильтровать элементы при вводе.

Пример:

<v-select
  v-model="selected"
  :items="items"
  label="Поиск"
  clearable
></v-select>

Если требуется более сложная логика поиска, используется свойство filter.

filter (item, queryText, itemText) {
  const text = itemText.toLowerCase()
  const query = queryText.toLowerCase()
  return text.includes(query)
}

Очистка значения

Для добавления кнопки очистки используется свойство clearable.

<v-select
  v-model="selected"
  :items="items"
  clearable
></v-select>

При нажатии на иконку значение v-model становится null.


Отключение компонента

v-select можно отключить с помощью свойства disabled.

<v-select
  v-model="selected"
  :items="items"
  disabled
></v-select>

Также возможно отключение отдельных элементов списка:

items: [
  { title: 'JavaScript', value: 'js' },
  { title: 'Python', value: 'py', disabled: true }
]

Плейсхолдер

Плейсхолдер отображается, когда значение не выбрано.

<v-select
  v-model="selected"
  :items="items"
  placeholder="Выберите значение"
></v-select>

Разница между label и placeholder:

Свойство Назначение
label подпись поля
placeholder текст внутри поля

Плотность компонента

Vuetify поддерживает несколько вариантов плотности интерфейса:

<v-select
  density="compact"
></v-select>

Варианты:

  • default
  • comfortable
  • compact

Это позволяет адаптировать интерфейс под различные сценарии: панели управления, формы, мобильные интерфейсы.


Валидация

v-select поддерживает систему правил (rules).

Пример обязательного поля:

<v-select
  v-model="selected"
  :items="items"
  :rules="[rules.required]"
  label="Категория"
></v-select>
rules: {
  required: value => !!value || 'Поле обязательно'
}

Если правило возвращает строку, она отображается как сообщение об ошибке.


Асинхронная загрузка данных

Список элементов может загружаться из API.

<v-select
  v-model="selected"
  :items="items"
  :loading="loading"
  label="Страны"
></v-select>
data() {
  return {
    items: [],
    loading: false
  }
},

async mounted() {
  this.loading = true
  const res = await fetch('/api/countries')
  this.items = await res.json()
  this.loading = false
}

Свойство loading отображает индикатор загрузки.


Кастомизация отображения элементов

Vuetify предоставляет слоты для изменения отображения элементов.

Слот item

Позволяет полностью контролировать внешний вид пункта списка.

<v-select
  v-model="selected"
  :items="items"
>
  <template v-slot:item="{ props, item }">
    <v-list-item v-bind="props">
      <v-list-item-title>
        {{ item.raw.name }}
      </v-list-item-title>
      <v-list-item-subtitle>
        ID: {{ item.raw.id }}
      </v-list-item-subtitle>
    </v-list-item>
  </template>
</v-select>

Слот selection

Используется для кастомного отображения выбранного значения.

<template v-slot:selection="{ item }">
  <v-chip>
    {{ item.title }}
  </v-chip>
</template>

Ограничение количества выбранных элементов

Можно ограничить число выбранных значений.

<v-select
  v-model="selected"
  :items="items"
  multiple
  :rules="[limit]"
></v-select>
limit: value =>
  value.length <= 3 || 'Можно выбрать не более 3 элементов'

Работа с объектами

Иногда требуется хранить не значение, а весь объект.

Для этого используется return-object.

<v-select
  v-model="selected"
  :items="items"
  item-title="name"
  return-object
></v-select>

Теперь v-model содержит объект:

selected = {
  id: 1,
  name: 'JavaScript'
}

Управление раскрытием меню

Меню выпадающего списка можно контролировать программно.

<v-select
  v-model="selected"
  :items="items"
  v-model:menu="menu"
></v-select>
data() {
  return {
    menu: false
  }
}

Это позволяет:

  • открывать меню программно
  • закрывать при определённых действиях
  • синхронизировать состояние интерфейса

Использование внутри форм

v-select часто используется внутри v-form.

<v-form ref="form">
  <v-select
    v-model="category"
    :items="categories"
    :rules="[rules.required]"
    label="Категория"
  ></v-select>
</v-form>

Методы формы:

this.$refs.form.validate()
this.$refs.form.reset()
this.$refs.form.resetValidation()

Производительность при больших списках

При работе с большими массивами элементов (тысячи записей) рекомендуется:

  1. Использовать виртуализацию списка
  2. Загружать данные частями
  3. Применять серверный поиск

Часто используется связка:

  • v-autocomplete
  • серверный API
  • дебаунс ввода

Основные свойства v-select

Свойство Назначение
items список элементов
v-model выбранное значение
label подпись поля
placeholder текст внутри поля
multiple множественный выбор
chips отображение чипов
clearable кнопка очистки
disabled отключение компонента
loading индикатор загрузки
item-title поле отображаемого текста
item-value поле значения
return-object возврат объекта

Основные события

Событие Назначение
update:modelValue изменение выбранного значения
update:menu изменение состояния меню
focus получение фокуса
blur потеря фокуса

Пример обработки:

<v-select
  v-model="selected"
  :items="items"
  @update:modelValue="onChange"
></v-select>
methods: {
  onChange(value) {
    console.log(value)
  }
}

Практический пример формы

<v-form>
  <v-select
    v-model="form.language"
    :items="languages"
    label="Язык"
    clearable
  ></v-select>

  <v-select
    v-model="form.frameworks"
    :items="frameworks"
    label="Фреймворки"
    multiple
    chips
  ></v-select>
</v-form>
data() {
  return {
    form: {
      language: null,
      frameworks: []
    },

    languages: [
      'JavaScript',
      'Python',
      'Go'
    ],

    frameworks: [
      'Vue',
      'React',
      'Angular'
    ]
  }
}

Такой подход позволяет создавать сложные формы с множеством связанных полей, используя единый API компонентов Vuetify.