Unpoly — это библиотека для создания интерактивных интерфейсов без полной перезагрузки страницы. Одним из распространённых сценариев является live-поиск, когда результаты обновляются динамически по мере ввода текста пользователем. Такой подход снижает нагрузку на сервер и улучшает UX за счёт мгновенного отклика интерфейса.
Live-поиск реализуется через комбинацию событий ввода и
AJAX-запросов. В Unpoly это делается с помощью атрибутов
up-target, up-url и методов
up.replace(), up.submit().
Ключевые моменты:
up-target указывает, какой элемент страницы будет
обновлён при выполнении запроса.up-url задаёт адрес, с которого будут загружаться
данные.input или keyup используются для
отправки запроса при изменении текста в поле поиска.Пример базовой разметки:
<form id="search-form" up-target="#results" up-url="/search" method="get">
<input type="text" name="query" id="search-input" placeholder="Введите запрос">
</form>
<div id="results">
<!-- Здесь будут отображаться результаты поиска -->
</div>
В этом примере каждый ввод текста может инициировать отправку формы
на сервер, после чего содержимое блока #results обновляется
результатами поиска.
Unpoly позволяет автоматически перехватывать формы и
ссылки, если указаны атрибуты up-target и
up-url. Для live-поиска это означает, что не требуется
писать отдельный обработчик событий, если форма настроена корректно.
<input type="text" name="query" placeholder="Поиск" up-target="#results" up-url="/search">
<div id="results"></div>
При вводе текста Unpoly может автоматически выполнять
GET-запрос на /search с параметром
query и заменять содержимое элемента
#results.
Для live-поиска важно ограничивать количество запросов при быстром
вводе текста. В Unpoly предусмотрена функция
up.fragment.send() в сочетании с debounce для
оптимизации:
const input = document.getElementById('search-input');
input.addEventListener('input', up.util.debounce(() => {
up.fragment.send(input.form, {
target: '#results'
});
}, 300));
Объяснение:
up.util.debounce(fn, delay) — создаёт задержку между
вызовами функции, предотвращая слишком частые AJAX-запросы.up.fragment.send(form, { target }) — выполняет
AJAX-запрос по данным формы и обновляет указанный блок страницы.Обычно при пустом поле поиска нужно очищать результаты. Это можно реализовать так:
input.addEventListener('input', up.util.debounce(() => {
if (!input.value.trim()) {
document.getElementById('results').innerHTML = '';
return;
}
up.fragment.send(input.form, { target: '#results' });
}, 300));
Unpoly позволяет легко отображать состояние загрузки через CSS-классы или события:
up.on('up:request', '#search-form', () => {
document.getElementById('results').classList.add('loading');
});
up.on('up:response', '#search-form', () => {
document.getElementById('results').classList.remove('loading');
});
up.on('up:error', '#search-form', (event) => {
document.getElementById('results').innerHTML = '<p>Ошибка при загрузке данных</p>';
});
up:request срабатывает при отправке запроса.up:response — после успешного получения данных.up:error — при ошибке на сервере или сетевой
ошибке.Unpoly автоматически обновляет URL при замене содержимого, если указаны соответствующие атрибуты. Это позволяет пользователю возвращаться к предыдущему состоянию поиска через кнопку «Назад» в браузере:
<form id="search-form" up-target="#results" up-url="/search" up-history="true">
<input type="text" name="query">
</form>
up-history="true" гарантирует, что каждый запрос
live-поиска будет добавлен в историю браузера.
Live-поиск часто требует передачи дополнительных параметров, например категорий или сортировки. Это можно сделать, добавив скрытые поля или обработчики:
<form id="search-form" up-target="#results" up-url="/search">
<input type="text" name="query">
<select name="category">
<option value="">Все категории</option>
<option value="books">Книги</option>
<option value="movies">Фильмы</option>
</select>
</form>
Unpoly автоматически сериализует форму и передаст все значения в AJAX-запросе.
Для улучшения производительности можно использовать кэширование:
up.on('up:before-request', '#search-form', (event) => {
const query = input.value.trim();
if (queryCache[query]) {
event.preventDefault();
up.replace('#results', queryCache[query]);
}
});
up.on('up:response', '#search-form', (event) => {
queryCache[input.value.trim()] = event.responseText;
});
event.preventDefault() отменяет стандартный
запрос.queryCache
позволяет повторно использовать их без новых AJAX-вызовов.Unpoly можно сочетать с динамической подгрузкой результатов по скроллу:
up.fragment.on('up:fragment:loaded', '#results', () => {
const sentinel = document.querySelector('#results .sentinel');
if (!sentinel) return;
const observer = new IntersectionObserver(entries => {
if (entries[0].isIntersecting) {
up.fragment.send('/search', { target: '#results', append: true, params: { query: input.value } });
}
});
observer.observe(sentinel);
});
append: true добавляет новые результаты к
существующим.IntersectionObserver позволяет загружать
новые данные только при достижении конца списка.Live-поиск в Unpoly сочетает простую настройку через HTML-атрибуты, мощные AJAX-возможности, поддержку истории браузера и оптимизацию запросов, что делает его эффективным инструментом для динамических интерфейсов.