Обёртки над Awesomplete позволяют изолировать логику инициализации автодополнения, стандартизировать конфигурации и упростить повторное использование компонентов в разных частях приложения. При прямом использовании Awesomplete код быстро начинает разрастаться: повторяются настройки, селекторы, обработчики событий, а управление экземплярами становится фрагментированным. Обёртка решает эту проблему, превращая библиотеку в единый абстрактный слой.
В основе любой обёртки над Awesomplete лежит принцип инкапсуляции:
Минимальная обёртка представляет собой функцию, которая принимает DOM-элемент и настройки, а возвращает готовый экземпляр Awesomplete:
function createAwesomplete(input, options = {}) {
return new Awesomplete(input, {
minChars: 1,
maxItems: 10,
autoFirst: true,
...options
});
}
Даже такой уровень уже устраняет дублирование базовых параметров и делает код предсказуемым.
Следующий уровень абстракции — конфигурационные профили. Они позволяют задавать поведение автодополнения в зависимости от сценария использования.
const AwesompleteProfiles = {
default: {
minChars: 1,
maxItems: 10
},
strict: {
minChars: 2,
maxItems: 5,
autoFirst: true
},
search: {
minChars: 0,
maxItems: 15,
autoFirst: true,
filter: Awesomplete.FILTER_STARTSWITH
}
};
function createAwesomplete(input, profile = "default", options = {}) {
const base = AwesompleteProfiles[profile] || AwesompleteProfiles.default;
return new Awesomplete(input, {
...base,
...options
});
}
Такой подход позволяет стандартизировать поведение интерфейса по всему приложению, избегая расхождения UX.
При усложнении логики функциональный стиль становится ограниченным. Классическая обёртка позволяет управлять состоянием и добавлять дополнительные методы поверх Awesomplete.
class AwesompleteWrapper {
constructor(input, options = {}) {
this.input = input;
this.options = options;
this.instance = new Awesomplete(input, {
minChars: 1,
maxItems: 10,
...options
});
this._bindEvents();
}
_bindEvents() {
this.input.addEventListener("awesomplete-selectcomplete", (e) => {
this.onSelect(e);
});
}
onSelect(event) {
// переопределяемое поведение
}
setList(list) {
this.instance.list = list;
}
open() {
this.instance.evaluate();
}
close() {
this.instance.close();
}
destroy() {
this.instance = null;
}
}
Здесь обёртка начинает выполнять роль контроллера, который не только создаёт экземпляр, но и управляет взаимодействием с ним.
Для сложных интерфейсов важно иметь возможность вмешиваться в разные этапы работы автодополнения. Это достигается через систему хуков.
class HookedAwesomplete {
constructor(input, options = {}) {
this.input = input;
this.hooks = {
beforeOpen: [],
afterSelect: [],
beforeEvaluate: []
};
this.instance = new Awesomplete(input, options);
this._init();
}
_init() {
this.input.addEventListener("awesomplete-open", () => {
this._runHooks("beforeOpen");
});
this.input.addEventListener("awesomplete-selectcomplete", (e) => {
this._runHooks("afterSelect", e);
});
}
_runHooks(name, payload) {
this.hooks[name].forEach(fn => fn(payload));
}
use(hookName, fn) {
if (this.hooks[hookName]) {
this.hooks[hookName].push(fn);
}
}
}
Такой слой позволяет добавлять поведение без изменения основной логики. Например, можно логировать выбор пользователя или модифицировать список перед отображением.
В больших приложениях важно централизованно управлять созданием экземпляров. Фабрика обёрток решает задачу унификации.
function AwesompleteFactory(globalOptions = {}) {
return {
create(input, options = {}) {
return new Awesomplete(input, {
...globalOptions,
...options
});
},
createWrapped(input, options = {}) {
return new AwesompleteWrapper(input, {
...globalOptions,
...options
});
}
};
}
Фабрика обеспечивает единый источник конфигурации и позволяет переключать поведение системы без изменения кода компонентов.
В реальных сценариях список данных редко бывает статичным. Обёртка может инкапсулировать асинхронную загрузку.
class AsyncAwesomplete {
constructor(input, fetcher, options = {}) {
this.input = input;
this.fetcher = fetcher;
this.instance = new Awesomplete(input, options);
this._bind();
}
_bind() {
this.input.addEventListener("input", async () => {
const value = this.input.value;
if (value.length < 2) return;
const data = await this.fetcher(value);
this.instance.list = data;
});
}
}
Здесь Awesomplete перестаёт быть статическим компонентом и превращается в адаптер к внешнему API.
Современный подход предполагает не наследование, а композицию. Несколько небольших обёрток могут комбинироваться.
function withDebounce(wrapper, delay = 300) {
let timer;
const originalFetch = wrapper.fetch;
wrapper.fetch = function(value) {
clearTimeout(timer);
timer = setTimeout(() => {
originalFetch.call(wrapper, value);
}, delay);
};
return wrapper;
}
Такой паттерн позволяет добавлять поведение без изменения исходного класса.
В некоторых интерфейсах Awesomplete должен работать не с одним input, а с группой элементов или нестандартной структурой DOM.
function bindAwesompleteToField(selector, options = {}) {
const element = document.querySelector(selector);
if (!element) return null;
const instance = new Awesomplete(element, options);
return {
element,
instance,
setValue(value) {
element.value = value;
},
getValue() {
return element.value;
}
};
}
Такая обёртка скрывает работу с DOM и предоставляет минимальный API для управления полем ввода.
При использовании множества обёрток важно контролировать очистку ресурсов. Awesomplete не всегда автоматически освобождает обработчики, поэтому обёртка должна предоставлять метод уничтожения состояния.
class ManagedAwesomplete {
constructor(input, options = {}) {
this.input = input;
this.instance = new Awesomplete(input, options);
this._handlers = [];
}
addEvent(event, handler) {
this.input.addEventListener(event, handler);
this._handlers.push({ event, handler });
}
destroy() {
this._handlers.forEach(({ event, handler }) => {
this.input.removeEventListener(event, handler);
});
this._handlers = [];
this.instance = null;
}
}
Такой подход предотвращает утечки памяти в SPA и динамических интерфейсах.
На практике обёртки редко существуют изолированно. Чаще всего они формируют слоистую архитектуру:
Комбинация этих уровней превращает Awesomplete из простой библиотеки автодополнения в ядро расширяемой системы ввода данных, где каждый слой решает строго определённую задачу и не пересекается с другими слоями по ответственности.