Автокомплит — это механизм, позволяющий пользователю вводить текст в поле поиска или форму, автоматически предлагая подсказки, основанные на уже введённой части текста. Этот механизм активно используется в поисковых системах, интернет-магазинах и других веб-приложениях для улучшения взаимодействия с пользователем. В Svelte создание автокомплита и поисковой системы — это задача, которая может быть решена с минимальными усилиями, используя реактивные возможности фреймворка и его простоту.
Автокомплит в Svelte основан на динамическом изменении списка предложений в зависимости от того, что пользователь вводит в поле ввода. Структура компонента будет включать два основных элемента:
Важной особенностью является реактивность: при изменении значения в поле ввода автоматически обновляется список предложений.
Начнём с создания простого поля ввода с привязанным значением. Для
этого создадим компонент Svelte, где текст из поля ввода будет храниться
в переменной query.
<script>
let query = '';
</script>
<input type="text" bind:value={query} placeholder="Поиск..." />
Здесь используется двусторонняя привязка bind:value,
которая позволяет синхронизировать переменную query с
содержимым поля ввода. Это значит, что каждый раз, когда пользователь
будет изменять значение в поле, переменная будет автоматически
обновляться.
Теперь, когда у нас есть значение в поле ввода, необходимо создать динамически обновляемый список предложений. Для этого нужно использовать фильтрацию данных, основанную на тексте запроса. Рассмотрим массив данных, который будет содержать варианты для автокомплита.
<script>
let query = '';
const suggestions = [
'Автомобили',
'Австралия',
'Автономия',
'Автокомплит',
'Авиация',
'Август',
'Автострада',
'Автоматизация'
];
$: filteredSuggestions = suggestions.filter(item =>
item.toLowerCase().includes(query.toLowerCase())
);
</script>
В этом примере массив suggestions содержит список слов,
и с помощью реактивного выражения $: создаётся новый список
filteredSuggestions, который фильтрует исходный массив по
введённому запросу. Мы используем метод toLowerCase(),
чтобы обеспечить нечувствительность поиска к регистру.
Теперь необходимо отобразить отфильтрованный список предложений. Для
этого можно использовать конструкцию {#each} в Svelte,
которая позволяет итерационно выводить данные.
{#if query && filteredSuggestions.length > 0}
<ul>
{#each filteredSuggestions as suggestion}
<li>{suggestion}</li>
{/each}
</ul>
{/if}
Здесь проверяется, что запрос не пустой и что есть хотя бы одно
предложение для отображения. С помощью {#each} мы выводим
список всех отфильтрованных предложений.
Чтобы добавить функциональность выбора предложения, можно добавлять обработчик клика. Когда пользователь кликает на элемент из списка, текст в поле ввода будет заменён на выбранное предложение.
<script>
function selectSuggestion(suggestion) {
query = suggestion;
}
</script>
{#if query && filteredSuggestions.length > 0}
<ul>
{#each filteredSuggestions as suggestion}
<li on:click={() => selectSuggestion(suggestion)}>{suggestion}</li>
{/each}
</ul>
{/if}
Теперь, когда пользователь кликает на один из вариантов, функция
selectSuggestion обновляет значение переменной
query на выбранный элемент, автоматически заполнив поле
ввода.
При создании автокомплита важно учесть производительность, особенно если количество предложений может быть большим или если поиск осуществляется через API. Для улучшения производительности часто используется техника дебаунсинга (debouncing), которая позволяет уменьшить количество запросов, выполняемых в ответ на быстрое изменение текста в поле ввода.
Дебаунсинг задерживает выполнение функции, пока пользователь не прекратит вводить текст на определённое время. Для реализации дебаунсинга в Svelte можно использовать таймер, который будет сбрасываться каждый раз, когда пользователь вводит новый символ.
<script>
import { onDestroy } from 'svelte';
let query = '';
const suggestions = [
'Автомобили', 'Австралия', 'Автономия', 'Автокомплит',
'Авиация', 'Август', 'Автострада', 'Автоматизация'
];
let timer;
$: {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
filteredSuggestions = suggestions.filter(item =>
item.toLowerCase().includes(query.toLowerCase())
);
}, 300); // Задержка 300 мс
}
$: filteredSuggestions = [];
</script>
<input type="text" bind:value={query} placeholder="Поиск..." />
{#if query && filteredSuggestions.length > 0}
<ul>
{#each filteredSuggestions as suggestion}
<li>{suggestion}</li>
{/each}
</ul>
{/if}
Здесь функция setTimeout сбрасывается каждый раз при
изменении значения в поле ввода. Когда пользователь перестаёт вводить
текст на 300 миллисекунд, выполняется фильтрация и обновление списка
предложений.
Если список предложений слишком большой, его можно загружать
динамически с сервера через API. Например, с помощью функции
fetch можно отправить запрос к серверу для получения
предложений, основанных на введённом запросе.
<script>
let query = '';
let filteredSuggestions = [];
$: {
if (query.length >= 3) {
fetch(`https://api.example.com/search?q=${query}`)
.then(res => res.json())
.then(data => {
filteredSuggestions = data.suggestions;
});
} else {
filteredSuggestions = [];
}
}
</script>
<input type="text" bind:value={query} placeholder="Поиск..." />
{#if query && filteredSuggestions.length > 0}
<ul>
{#each filteredSuggestions as suggestion}
<li>{suggestion}</li>
{/each}
</ul>
{/if}
Здесь запрос отправляется на сервер только тогда, когда длина введённого текста составляет 3 символа или более. Это позволяет избежать лишних запросов на сервер при каждом вводе символа.
Когда данные загружаются с сервера, важно обработать возможные ошибки и предоставить пользователю информацию о процессе загрузки. Для этого можно добавить индикатор загрузки и обработку ошибок.
<script>
let query = '';
let filteredSuggestions = [];
let loading = false;
let error = null;
$: {
if (query.length >= 3) {
loading = true;
error = null;
fetch(`https://api.example.com/search?q=${query}`)
.then(res => res.json())
.then(data => {
filteredSuggestions = data.suggestions;
})
.catch(err => {
error = 'Ошибка загрузки данных';
})
.finally(() => {
loading = false;
});
} else {
filteredSuggestions = [];
}
}
</script>
<input type="text" bind:value={query} placeholder="Поиск..." />
{#if loading}
<p>Загрузка...</p>
{:else if error}
<p>{error}</p>
{:else if filteredSuggestions.length > 0}
<ul>
{#each filteredSuggestions as suggestion}
<li>{suggestion}</li>
{/each}
</ul>
{/if}
Здесь в случае загрузки данных отображается текст “Загрузка…”, а в случае ошибки — сообщение об ошибке.
С помощью Svelte создание компонента автокомплита и поиска оказывается простым и интуитивно понятным процессом. Реактивность Svelte позволяет легко обновлять UI на основе введённого текста, а добавление дополнительных функций, таких как дебаунсинг, динамическая загрузка данных с API и обработка ошибок, делает компонент более функциональным и производительным.