Управление жизненным циклом

Жизненный цикл экземпляра автодополнения в Awesomplete начинается с момента привязки к DOM-элементу и заканчивается явным или неявным удалением обработчиков событий и ссылок, удерживающих объект в памяти. Корректное управление этим процессом особенно важно в условиях динамических интерфейсов, SPA-приложений и повторного создания компонентов.

Создание экземпляра Awesomplete обычно происходит после того, как DOM-элемент ввода уже существует и доступен для манипуляций. Базовая инициализация заключается в передаче input-элемента в конструктор:

const input = document.querySelector("#search");
const awesomplete = new Awesomplete(input, {
  minChars: 1,
  maxItems: 10,
  autoFirst: true
});

На этапе инициализации происходят следующие действия:

  • создание внутреннего состояния экземпляра;
  • привязка обработчиков событий к input;
  • подготовка структуры списка подсказок;
  • создание контейнера dropdown (если требуется);
  • сохранение ссылок на DOM-элементы.

Awesomplete не требует отдельного вызова метода init, так как вся логика запускается в конструкторе.

Привязка к DOM и установка источника данных

После создания экземпляра ключевым этапом жизненного цикла становится настройка источника данных. В Awesomplete он может задаваться как массив, функция или динамический источник.

awesomplete.list = ["Apple", "Banana", "Cherry"];

или

awesomplete.list = function(text, callback) {
  fetch(`/api/suggest?q=${encodeURIComponent(text)}`)
    .then(r => r.json())
    .then(data => callback(data));
};

При изменении списка происходит пересборка внутренних структур, но сам экземпляр остаётся активным. Это важно: обновление list не пересоздаёт объект, а модифицирует его состояние.

Обработка событий ввода

Основной цикл работы Awesomplete связан с событиями input-элемента. На этапе привязки устанавливаются обработчики:

  • input — анализ введённого текста;
  • keydown — управление навигацией;
  • blur — закрытие списка при потере фокуса;
  • focus — возможное повторное открытие списка.

Каждое событие влияет на внутреннее состояние:

  • вычисление текущего запроса;
  • фильтрация списка;
  • управление видимостью dropdown;
  • обновление активного элемента.

Особенность архитектуры заключается в том, что Awesomplete не использует внешний цикл рендеринга — всё происходит синхронно внутри обработчиков событий.

Открытие и закрытие списка подсказок

Контроль видимости выпадающего списка является центральной частью жизненного цикла.

Открытие происходит при выполнении условий:

  • количество символов ≥ minChars;
  • наличие совпадений в источнике;
  • отсутствие блокировки состояния.

Закрытие инициируется:

  • потерей фокуса;
  • нажатием Escape;
  • отсутствием результатов;
  • программным вызовом.
awesomplete.open();
awesomplete.close();

При открытии создаётся или активируется DOM-контейнер списка. При закрытии он скрывается, но не уничтожается, что позволяет повторно использовать элемент без пересоздания.

Перерисовка и обновление состояния

Внутренний цикл обновления запускается при каждом изменении ввода. Он включает:

  • нормализацию строки запроса;
  • фильтрацию списка;
  • сортировку результатов (если задан comparator);
  • ограничение количества элементов через maxItems;
  • построение DOM-элементов списка.

Каждое обновление заменяет содержимое dropdown, но не пересоздаёт основной контейнер.

Управление состоянием активного элемента

Awesomplete поддерживает концепцию активного (highlighted) элемента списка. Управление этим состоянием происходит через клавиатурные события:

  • ArrowDown — переход к следующему элементу;
  • ArrowUp — переход к предыдущему;
  • Enter — выбор текущего элемента.

Внутренне хранится индекс активного элемента, который изменяется при навигации:

awesomplete.index = 0;

Изменение индекса вызывает обновление визуального выделения.

Программный выбор значения

Жизненный цикл включает этап, на котором значение из списка передаётся обратно в input:

awesomplete.select(0);

или при пользовательском выборе:

awesomplete.replace("Selected value");

На этом этапе происходит:

  • установка значения input;
  • закрытие списка;
  • генерация событий выбора;
  • сброс состояния индекса.

Динамическое обновление данных

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

awesomplete.list = newList;

или обновление на основе внешнего API.

При этом жизненный цикл не прерывается: объект продолжает существовать, а изменяется только его data-layer.

Повторное использование экземпляра

Awesomplete допускает многократное использование одного и того же экземпляра с разными наборами данных и состояниями ввода. Это достигается за счёт:

  • отсутствия жёсткой привязки к одному dataset;
  • переиспользуемых DOM-элементов;
  • изолированного состояния внутри объекта.

При смене контекста достаточно:

awesomplete.list = [];
awesomplete.close();

или установки нового списка.

Уничтожение экземпляра и очистка ресурсов

В стандартной реализации Awesomplete не всегда предоставляет явный метод destroy, поэтому очистка выполняется вручную. Основная задача на этом этапе — устранение утечек памяти и разрыв всех связей с DOM.

Типичный процесс деинициализации:

input.removeEventListener("input", awesomplete.inputHandler);
input.removeEventListener("keydown", awesomplete.keyHandler);
input.removeEventListener("blur", awesomplete.blurHandler);

awesomplete.close();
awesomplete = null;

Если создавался dropdown-контейнер, он также должен быть удалён:

awesomplete.ul.parentNode.removeChild(awesomplete.ul);

Ключевые действия при завершении жизненного цикла:

  • удаление обработчиков событий;
  • очистка ссылок на DOM-элементы;
  • уничтожение вспомогательных узлов;
  • обнуление ссылки на экземпляр.

Управление в SPA и динамических интерфейсах

В одностраничных приложениях жизненный цикл Awesomplete часто привязан к жизненному циклу компонентов интерфейса. При этом критичны следующие моменты:

  • повторная инициализация на одном input недопустима без очистки предыдущего экземпляра;
  • скрытие компонента не равно его уничтожению;
  • переход между страницами требует явного разрыва связей.

При интеграции с компонентной архитектурой важно учитывать:

  • создание экземпляра при mount;
  • обновление list при изменении props/state;
  • уничтожение при unmount.

Поведение при повторной инициализации

Повторная инициализация без очистки приводит к:

  • дублированию обработчиков событий;
  • множественным вызовам фильтрации;
  • некорректной работе навигации;
  • утечкам памяти.

Поэтому корректный жизненный цикл всегда включает контроль единственности экземпляра на один input-элемент.

Особенности хранения состояния

Внутреннее состояние Awesomplete включает:

  • текущий запрос;
  • активный индекс;
  • список данных;
  • состояние видимости dropdown;
  • ссылки на DOM.

Это состояние не синхронизируется с внешним миром автоматически, поэтому управление жизненным циклом требует явного контроля при изменениях интерфейса.

Поведение при потере контекста DOM

Если input-элемент удаляется из DOM без предварительной очистки:

  • обработчики событий продолжают существовать;
  • ссылки на элемент удерживаются в памяти;
  • dropdown может остаться активным.

Это создаёт типичную проблему утечек в долгоживущих приложениях. Управление жизненным циклом в таких случаях сводится к обязательному разрыву всех связей до удаления узла.