Библиотека Unpoly предоставляет мощные инструменты для динамического обновления страниц без полной перезагрузки, включая реализацию бесконечной прокрутки (infinite scroll). Эта функциональность позволяет подгружать новые данные по мере прокрутки пользователя, повышая интерактивность и снижая нагрузку на сервер.
Бесконечная прокрутка в Unpoly строится на сочетании:
up.link,
up.visit или up.render).up-target, up-on-load).Ключевой принцип: новые данные загружаются и вставляются в документ без перезагрузки страницы, а URL может обновляться при необходимости для корректного использования истории браузера.
Стандартный шаблон включает контейнер, куда будут добавляться новые элементы, и элемент-загрузчик:
<div id="items-container" up-target="this">
<div class="item">Элемент 1</div>
<div class="item">Элемент 2</div>
<div class="item">Элемент 3</div>
</div>
<button id="load-more"
up-target="#items-container"
up-append=".item"
up-url="/items?page=2"
up-on-click="loadNextPage">
Загрузить ещё
</button>
Ключевые атрибуты:
up-target: указывает контейнер, в который будут
вставляться новые элементы.up-append: определяет, какие элементы вставлять из
полученного фрагмента.up-url: адрес следующей страницы данных.up-on-click: привязка обработчика для кастомной логики
(может быть использована для автоматической загрузки при скролле).Чтобы элементы подгружались автоматически при достижении нижней
границы контейнера, используется событие scroll в сочетании
с методами Unpoly:
function setupInfiniteScroll() {
const container = document.getElementById('items-container');
window.addEventListener('scroll', () => {
const scrollPosition = window.scrollY + window.innerHeight;
const threshold = container.offsetTop + container.offsetHeight;
if (scrollPosition > threshold - 100) {
loadNextPage();
}
});
}
function loadNextPage() {
const button = document.getElementById('load-more');
if (!button) return;
up.follow(button); // инициирует запрос, как при клике
}
Особенности реализации:
up.follow(element) выполняет тот же запрос, что и
нажатие кнопки, включая все up-* атрибуты.threshold - 100 добавляет небольшой запас, чтобы
загрузка начиналась заранее и пользователь не видел пустой зоны.Unpoly поддерживает точечное обновление DOM. Для бесконечной прокрутки важно правильно настроить селекторы:
up-append: добавляет новые элементы в конец
контейнера.up-prepend: вставляет элементы в начало.up-replace: заменяет существующее содержимое
контейнера.Пример использования up-append:
<div id="messages" up-target="this">
<div class="message">Сообщение 1</div>
</div>
<div id="load-messages"
up-target="#messages"
up-append=".message"
up-url="/messages?page=2">
</div>
При каждом запросе новые .message элементы будут
добавляться последовательно, сохраняя старые.
Бесконечная прокрутка часто подразумевает работу с историей браузера. Unpoly позволяет:
up:history:push.up-on-load для инициализации новых
элементов после вставки.Пример:
<div id="articles" up-target="this" up-on-load="initLazyImages()">
<article class="post">Пост 1</article>
</div>
Событие up:after-append может использоваться для
динамических действий после добавления новых элементов:
up.on('up:after-append', '#articles', (event) => {
console.log('Новые посты добавлены:', event.fragments);
});
Для больших списков важно учитывать:
let scrollTimeout;
window.addEventListener('scroll', () => {
if (scrollTimeout) clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(() => loadNextPage(), 200);
});
loading="lazy" или кастомных функций в
up-on-load.page в URL и корректно увеличивать его на сервере.На сервере необходимо отдавать HTML-фрагменты,
соответствующие селектору up-append. Пример для
Express.js:
app.get('/items', (req, res) => {
const page = parseInt(req.query.page) || 1;
const items = getItems(page); // массив элементов
res.render('items_fragment', { items });
});
Фрагмент items_fragment содержит только новые
.item элементы без обертки страницы. Это минимизирует объём
данных и ускоряет загрузку.
up:fragment:loading для отображения
индикатора загрузки.up.abort.Бесконечная прокрутка в Unpoly позволяет строить динамичные, отзывчивые интерфейсы, объединяя преимущества фрагментного обновления и событийной модели библиотеки. При правильной настройке селекторов, контроля запросов и оптимизации рендеринга достигается плавная и эффективная подгрузка данных.