Приветствую
Разберем пример создания элемента автодополнения для 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>