Использование с Svelte

Awesomplete представляет собой минималистичную, но функционально гибкую библиотеку автодополнения, изначально рассчитанную на работу с «чистым» DOM. При использовании в реактивных фреймворках, таких как Svelte, требуется учитывать особенности жизненного цикла компонентов и реактивности, чтобы корректно синхронизировать внешний DOM-объект с состоянием приложения.

Svelte компилирует компоненты в императивный код, напрямую работающий с DOM, поэтому интеграция Awesomplete проходит проще, чем в более абстрактных фреймворках. Тем не менее, библиотека не является реактивной по своей природе, и её состояние необходимо синхронизировать вручную.


Подключение Awesomplete в Svelte-проект

Установка библиотеки:

npm install awesomplete

Подключение стилей:

import "awesomplete/awesomplete.css";

Импорт самой библиотеки:

import Awesomplete from "awesomplete";

Awesomplete требует наличия DOM-элемента <input>, поэтому инициализация должна происходить после монтирования компонента.


Базовая инициализация в компоненте Svelte

Ключевой механизм интеграции — использование onMount, обеспечивающего доступ к DOM.

<script>
  import { onMount } from "svelte";
  import Awesomplete from "awesomplete";
  import "awesomplete/awesomplete.css";

  let input;
  let awesomplete;

  const list = ["Apple", "Apricot", "Banana", "Blueberry", "Cherry"];

  onMount(() => {
    awesomplete = new Awesomplete(input, {
      list,
      minChars: 1,
      maxItems: 10,
      autoFirst: true
    });
  });
</script>

<input bind:this={input} placeholder="Введите фрукт" />

Ключевые моменты интеграции

  • bind:this используется для получения ссылки на DOM-элемент.
  • onMount гарантирует, что элемент уже существует.
  • экземпляр Awesomplete создаётся один раз при монтировании.

Реактивное обновление списка данных

Awesomplete не отслеживает изменения массива автоматически. Любое изменение данных требует ручного обновления.

Обновление через свойство list

<script>
  import { onMount } from "svelte";
  import Awesomplete from "awesomplete";

  let input;
  let awesomplete;

  let fruits = ["Apple", "Banana", "Cherry"];

  function updateList() {
    if (awesomplete) {
      awesomplete.list = fruits;
    }
  }

  onMount(() => {
    awesomplete = new Awesomplete(input, {
      list: fruits
    });
  });

  function addFruit() {
    fruits = [...fruits, "Orange"];
    updateList();
  }
</script>

<input bind:this={input} />
<button on:click={addFruit}>Добавить</button>

Особенность поведения

Awesomplete хранит копию списка внутри экземпляра, поэтому изменение массива Svelte само по себе не вызывает обновления автодополнения.


Использование динамического источника данных

Часто список формируется на основе API или вычислений. В таком случае важна синхронизация при изменении переменных.

<script>
  import { onMount } from "svelte";
  import Awesomplete from "awesomplete";

  let input;
  let awesomplete;

  let query = "";
  let items = [];

  $: filtered = items.filter(i =>
    i.toLowerCase().includes(query.toLowerCase())
  );

  $: if (awesomplete) {
    awesomplete.list = filtered;
  }

  onMount(() => {
    awesomplete = new Awesomplete(input, {
      list: filtered,
      minChars: 1
    });
  });
</script>

<input bind:this={input} bind:value={query} />

Реактивный блок $:

Svelte позволяет автоматически отслеживать изменения и обновлять awesomplete.list.


Асинхронная загрузка данных

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

<script>
  import { onMount } from "svelte";
  import Awesomplete from "awesomplete";

  let input;
  let awesomplete;

  let cities = [];

  async function loadCities() {
    const res = await fetch("/api/cities");
    cities = await res.json();

    if (awesomplete) {
      awesomplete.list = cities;
    }
  }

  onMount(() => {
    awesomplete = new Awesomplete(input, {
      list: []
    });

    loadCities();
  });
</script>

<input bind:this={input} />

Поведение при асинхронной загрузке

  • Инициализация происходит с пустым списком.
  • После получения данных список обновляется вручную.

Настройка пользовательского поведения

Awesomplete предоставляет набор опций, которые могут быть адаптированы под реактивную среду Svelte.

awesomplete = new Awesomplete(input, {
  list,
  minChars: 2,
  maxItems: 5,
  autoFirst: true,
  filter: (text, input) => {
    return text.includes(input);
  },
  item: (text, input) => {
    return Awesomplete.ITEM(text, input);
  }
});

Значимые параметры

  • minChars — минимальное количество символов для активации.
  • maxItems — ограничение числа отображаемых элементов.
  • filter — кастомная логика фильтрации.
  • item — кастомный рендер элемента списка.

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

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

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

<script>
  import { onMount, onDestroy } from "svelte";
  import Awesomplete from "awesomplete";

  let input;
  let awesomplete;

  onMount(() => {
    awesomplete = new Awesomplete(input, {
      list: ["A", "B", "C"]
    });
  });

  onDestroy(() => {
    awesomplete = null;
  });
</script>

<input bind:this={input} />

Причина явного сброса

Awesomplete не предоставляет полноценного метода destroy, поэтому освобождение ссылки предотвращает утечки в SPA.


Работа с событиями Awesomplete

Awesomplete генерирует события, которые можно использовать в Svelte через addEventListener.

<script>
  import { onMount } from "svelte";
  import Awesomplete from "awesomplete";

  let input;
  let awesomplete;

  onMount(() => {
    awesomplete = new Awesomplete(input, {
      list: ["JavaScript", "TypeScript", "Svelte"]
    });

    input.addEventListener("awesomplete-selectcomplete", (e) => {
      console.log("Выбран элемент:", e.text.value);
    });
  });
</script>

<input bind:this={input} />

Основные события

  • awesomplete-selectcomplete — выбор элемента.
  • awesomplete-open — открытие списка.
  • awesomplete-close — закрытие списка.

Кастомизация через Svelte-реактивность

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

Пример реактивного обёрточного компонента

<script>
  import { onMount } from "svelte";
  import Awesomplete from "awesomplete";

  export let items = [];
  export let value = "";

  let input;
  let awesomplete;

  $: if (awesomplete) {
    awesomplete.list = items;
  }

  onMount(() => {
    awesomplete = new Awesomplete(input, {
      list: items
    });

    input.addEventListener("awesomplete-selectcomplete", (e) => {
      value = e.text.value;
    });
  });
</script>

<input bind:this={input} bind:value={value} />

Результат архитектуры

  • внешний компонент управляет данными;
  • Awesomplete остаётся изолированным DOM-слоем;
  • реактивность Svelte обеспечивает синхронизацию.

Особенности производительности в Svelte-среде

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

  • обновление list лучше выполнять батчами;
  • избегается пересоздание экземпляра;
  • предпочтительно изменять list, а не пересоздавать Awesomplete.

Инкапсуляция логики автодополнения

В Svelte часто целесообразно вынести Awesomplete в отдельный слой логики, чтобы компонент оставался декларативным.

function createAutocomplete(input, list) {
  const instance = new Awesomplete(input, { list });

  return {
    setList(newList) {
      instance.list = newList;
    },
    destroy() {
      instance = null;
    }
  };
}

Такая структура позволяет отделить UI от механики автодополнения и упрощает поддержку сложных форм.


Особенности взаимодействия с формами Svelte

При использовании Svelte-форм Awesomplete работает поверх стандартного <input> без вмешательства в механизм bind:value, однако важно учитывать:

  • Awesomplete изменяет значение input напрямую;
  • Svelte синхронизирует value через binding;
  • возможны гонки обновления при сложных сценариях фильтрации.

Типичная стратегия — доверять DOM как источнику истины для значения input, а Svelte использовать для внешнего состояния формы.