Создаем аналог 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
  • Рейтинг: 1
  • Просмотров: 1120
  • Комментариев: 0
  • Создан: 02.03.2021 15:25

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

Ваши предложения и пожелания пишите на pro@kosmom.ru

Теги

ajax axios backup bootstrap core framework eloquent excel home project html ios javascript keep-alive kpi laravel legacy mvp orm php rip scroll solid timestamp undefined vue vuetify watch безопасность биометрический паспорт ваша любаша для путешествий загран на 10 лет загран паспорт загранпаспорт нового образца зимние книги как заполнить анкеты кеширование книги на новый год логирование мцф недвижимость новогодние книги образец заполнения антеты паспорт для путешествий паспорт нового поколения печать продукт проектирование прокси разработка ремонт ремонт в апартаментах ремонт нежилого помещения самокат сдача сколько стоил ремонт апартаментов спорт стандарты таблица финансы хостинг цена ремонта что почитать зимой юзабилити

Случайный пост

29.01.2014 13:52
Порядок в прихожей (она же коридор)