Создаем аналог select2 стандартными средствами vuetify

Приветствую
Разберем пример создания элемента автодополнения для vuetify 2.2 (на текущий момент). С подгрузкой данных с сервера при вводе данных пользователем
Пишу об этом, т.к. на текущий момент нет понятной инструкции по устройству данных компонентов.
Начнем с того, что в vuetify есть стандартный элемент v-autocomplete, но он работает совершенно не так как нужно. Его основное назначение позволить выбрать значение из доступных элементов или не выбрать ничего. Если вам нужно именно такое решение - используйте именно v-autocomplete
Если вы хотите сделать некий автокомплит в виде подсказок, но позволить пользователь ввести значение с клавиатуры - вам необходимо использовать v-combobox
И не спрашивайте почему их не объединили в один.


Теперь для динамической подгрузки подсказок с сервера - в стандартных средствах vuetify нет предусмотренных элементов, вам придется связывать имеющиеся свойства для достижения цели

Имейте в виду, как работает комбобокс. Внутри у него содержится селект и текстовое поле, соответственно для каждого из значений нужно задать переменную, на которую будем опираться
Текстовый ввод зададим через собственную переменную search и обменивается через sync

<v-combobox
:search-input.sync="search"
...
/>


Соответственно - теперь мы можем наблюдать за переменной и производить нужные вызовы

Сразу заложите визуальный эффект загрузки loading (он нужен только для красоты и отзывчивости) и выпадающий список autocomplete

<v-combobox
:search-input.sync="search"
:items="autocomplete"
:loading="loading"
...
/>
data() {
    return {
      loading: false,
      search: "",
      autocomplete: [],
    }
  },


Примерно такой набор минимальных параметров должен получиться для дальнейшей работы

Теперь, чтобы контролировать ввод и выполнять какие-либо события - можем вести наблюдение за переменной search

watch: {
    search(value) {
      this.autocomplete = []

      // debounce
      clearTimeout(this._searchTimerId)
      this._searchTimerId = setTimeout(() => {
        this.loadAutocomplete(value)
      }, 500) /* 500ms throttle */
    },
  },

Если мы не хотим делать запрос на каждое нажатие - принято каждое нажатие клавиши такие вещи через debounce, порядка пол секунды
Соответственно в финале остается сама реализация заполнения списка но с некоторыми особенностями

loadAutocomplete(value) {
if (!value) {
return
}
// устанавливаем минимальное количество символов для начала поиска
if (value.length <= 2) {
return
}
// данные которые придут на бек
const params = {
text: this.value
}

this.loading = true
this.$axios.$get(SEARCH_API_URL, { params }).then(r => {
this.loading = false
// преобразования необходимые для приведения данных бека в массив списка
r.data.forEach(item =>
this.autocomplete.push({
text: item.name,
route: {
name: "item-id",
params: {
id: item.id,
},
},
}),
)
})
},

Возвращаемый список можно не кастомизировать через слоты компонента, если вам нужно ограничиться одной строкой
Рекомендую сразу заложить в структуре параметры роутинга, если вы собираетесь прыгать по клику на эту сущность
Заключительный элемент может выглядеть следующим образом

<v-combobox
          label="Поиск"
          :items="autocomplete"
          :loading="loading"
          :search-input.sync="search"
          @change="routeTo"
          no-filter
          append-icon=""
          prepend-inner-icon="search"
          hide-details
item-value="id"
        />

no-filter - убирает дополнительную фильтрацию по найденным результатам
append-icon - убирает иконку выпадающего списка справа
Остается только описать событие происходящее по клику

routeTo(item) {
      if (typeof item === "string") {
        return
      }
      if (item === null) {
        return
      }
      this.$router.push(item.route)
    },

Самое главное теперь чтобы список содержал ключи
id - неповторяющийся
и text - выводимый пользователю

<v-select
:multiple="isMultiple(data)"
>
<template v-slot:selection="data">
<v-chip v-if="data.item.extra">
<v-avatar
class="elevation-10"
v-if="data.item.src"
left
:src="data.item.src"
/>
{{ data.item.name }}
</v-chip>
<template v-else>
{{ data.item.name }}
</template>
</template>
<template
v-slot:item="{ parent, item, tile }"
v-if="isMiltiple(data)"
>
<v-list-tile-action>
<v-checkbox :input-value="tile.props.value"></v-checkbox>
</v-list-tile-action>
<v-list-tile-avatar v-if="item.extra">
<v-avatar
size="36"
class="elevation-10"
left
:src="item.src"
/>
</v-list-tile-avatar>
<v-list-tile-content>
<v-list-tile-title v-html="item.name" />
</v-list-tile-content>
</template>
<template v-slot:item="{ parent, item, tile }" v-else>
{{ item.name }}
</template>
</v-select>
  • Автор: kosmom
  • Рейтинг: 0
  • Просмотров: 62
  • Комментариев: 0
  • Создан: 02.03.2021 15:25

Комментарии (0)