Awesomplete изначально создавалась как лёгкая vanilla-библиотека автодополнения без привязки к фреймворкам, поэтому при использовании в Vue основная задача заключается в правильной интеграции жизненного цикла компонента и DOM-элементов, чтобы избежать конфликтов между реактивностью Vue и прямыми DOM-манипуляциями Awesomplete.
Ключевой момент: Awesomplete работает напрямую с DOM-элементом
<input>, поэтому инициализация должна происходить
после монтирования компонента.
import Awesomplete from "awesomplete";
import "awesomplete/awesomplete.css";
export default {
data() {
return {
value: "",
awesomplete: null,
list: ["Apple", "Apricot", "Avocado", "Banana", "Blueberry"]
};
},
mounted() {
this.awesomplete = new Awesomplete(this.$refs.input, {
list: this.list,
minChars: 1,
autoFirst: true
});
}
};
<input ref="input" v-model="value" />
Важно учитывать, что v-model и Awesomplete работают
параллельно: Vue управляет значением, а Awesomplete управляет UI
подсказок.
При выборе элемента из списка Awesomplete не всегда автоматически синхронизирует значение с Vue-состоянием. Поэтому необходимо вручную отслеживать событие выбора.
mounted() {
this.awesomplete = new Awesomplete(this.$refs.input, {
list: this.list
});
this.$refs.input.addEventListener("awesomplete-selectcomplete", (e) => {
this.value = e.text.value;
});
}
Это гарантирует, что реактивное состояние Vue всегда соответствует выбранному значению.
Дополнительно полезно отслеживать ввод:
<input
ref="input"
v-model="value"
@input="onInput"
/>
methods: {
onInput() {
if (this.awesomplete) {
this.awesomplete.list = this.filteredList;
}
}
}
Во Vue данные часто приходят асинхронно или фильтруются на лету. Awesomplete позволяет обновлять список без пересоздания экземпляра.
computed: {
filteredList() {
return this.list.filter(item =>
item.toLowerCase().includes(this.value.toLowerCase())
);
}
},
watch: {
filteredList(newList) {
if (this.awesomplete) {
this.awesomplete.list = newList;
}
}
}
Такой подход позволяет связать реактивность Vue с внутренним состоянием Awesomplete без конфликтов.
Частый сценарий — получение подсказок с API.
methods: {
async fetchSuggestions(query) {
const res = await fetch(`/api/search?q=${query}`);
return await res.json();
},
async onInput() {
if (this.value.length < 2) return;
const results = await this.fetchSuggestions(this.value);
if (this.awesomplete) {
this.awesomplete.list = results;
this.awesomplete.evaluate();
}
}
}
В этом случае важно явно вызывать evaluate(), чтобы
Awesomplete пересчитал совпадения после обновления данных.
Без ограничения частоты вызовов API автодополнение может создавать лишнюю нагрузку. В Vue удобно использовать простой debounce.
methods: {
debounce(fn, delay) {
let timeout;
return (...args) => {
clearTimeout(timeout);
timeout = setTimeout(() => fn.apply(this, args), delay);
};
}
},
created() {
this.onIn put = this.debounce(this.onInput, 300);
}
Теперь запросы выполняются только после паузы ввода.
Awesomplete позволяет задавать форматирование элементов списка через
item и replace.
mounted() {
this.awesomplete = new Awesomplete(this.$refs.input, {
list: this.list,
item: (text, input) => {
const li = document.createElement("li");
li.innerHTML = text.replace(
new RegExp(input, "gi"),
match => `<strong>${match}</strong>`
);
return li;
},
replace: (text) => {
this.value = text.value;
}
});
}
Такой подход даёт полный контроль над тем, как выглядят подсказки.
Более структурированный вариант — обёртка в переиспользуемый компонент.
export default {
props: {
suggestions: {
type: Array,
default: () => []
}
},
data() {
return {
value: null,
awesomplete: null
};
},
mounted() {
this.awesomplete = new Awesomplete(this.$refs.input, {
list: this.suggestions
});
},
watch: {
suggestions(newVal) {
if (this.awesomplete) {
this.awesomplete.list = newVal;
}
}
}
};
<input ref="input" v-model="value" />
Такой компонент становится изолированным и не зависит от логики внешнего приложения.
Awesomplete предоставляет события, которые можно использовать для улучшения взаимодействия.
this.$refs.input.addEventListener("awesomplete-open", () => {
// можно, например, добавить класс активности
});
this.$refs.input.addEventListener("awesomplete-close", () => {
// очистка состояния UI
});
Дополнительно можно программно открывать список:
this.awesomplete.evaluate();
Во Vue 3 рекомендуется использовать Composition API и
onMounted.
import { ref, onMounted, watch } from "vue";
import Awesomplete from "awesomplete";
export default {
setup() {
const input = ref(null);
const value = ref("");
let awesomplete = null;
const list = ref(["Berlin", "Bern", "Barcelona"]);
onMounted(() => {
awesomplete = new Awesomplete(input.value, {
list: list.value
});
input.value.addEventListener("awesomplete-selectcomplete", (e) => {
value.value = e.text.value;
});
});
watch(list, (newList) => {
if (awesomplete) {
awesomplete.list = newList;
}
});
return { input, value, list };
}
};
Поскольку Awesomplete работает с DOM напрямую, важно очищать обработчики при уничтожении компонента.
beforeUnmount() {
if (this.awesomplete) {
this.awesomplete.destroy();
this.awesomplete = null;
}
}
Это предотвращает утечки памяти и некорректное поведение при повторном создании компонента.
Часто встречается ситуация, когда список обновляется, но UI не
пересчитывается. Причина — отсутствие вызова evaluate() или
неправильное обновление list.
Другой распространённый сценарий — попытка полностью управлять input через Vue без учёта того, что Awesomplete также изменяет его значение напрямую. Это приводит к конфликту состояний.
Корректная стратегия всегда заключается в том, чтобы считать Awesomplete только UI-слоем, а Vue — источником истины для данных.