Unpoly — это JavaScript-библиотека, предназначенная для улучшения UX веб-приложений за счёт динамической подгрузки фрагментов страниц без полной перезагрузки. Она строится на принципах прогрессивного улучшения: если JavaScript отключён, приложение продолжает работать как обычное многостраничное.
В основе работы лежит концепция фрагментов
(fragments) и целевых элементов
(targets). Фрагменты — это части HTML, которые могут быть
динамически обновлены. Целевой элемент — это контейнер, куда будет
вставлен новый контент.
up.target('main').render('/posts/42');
В этом примере /posts/42 подгружается в элемент с
атрибутом up-target="main".
Unpoly автоматически обрабатывает ссылки и формы, если они помечены
атрибутом up-target или находятся внутри контейнера с этим
атрибутом.
Пример ссылки с динамической подгрузкой:
<a href="/posts/42" up-target="main">Читать пост</a>
При клике содержимое <main up-target="main"> будет
заменено без полной перезагрузки страницы.
Пример формы с AJAX-подгрузкой:
<form action="/posts" method="post" up-target="main">
<input type="text" name="title">
<button type="submit">Создать</button>
</form>
Unpoly перехватывает отправку формы, отправляет данные через AJAX и обновляет указанный фрагмент страницы.
Unpoly поддерживает плавные переходы при подгрузке контента. Для этого используются CSS-классы и опции анимации:
up.render('/posts/42', { fade: true });
Можно определить собственные классы анимации через CSS:
.up-fade-in {
animation: fadeIn 0.3s ease-out;
}
.up-fade-out {
animation: fadeOut 0.3s ease-in;
}
Unpoly автоматически применяет их при замене содержимого целевого элемента.
Unpoly предоставляет богатый набор событий, которые позволяют интегрировать динамическое поведение:
up:fragment:loaded — вызывается после подгрузки нового
фрагмента.up:fragment:replaced — вызывается после замены
содержимого целевого элемента.up:request:error — вызывается при ошибке
AJAX-запроса.document.addEventListener('up:fragment:loaded', function(event) {
console.log('Фрагмент загружен:', event.fragment);
});
Эти события позволяют подключать дополнительную логику, например инициализацию виджетов или валидацию форм после обновления контента.
Unpoly автоматически управляет историей браузера. При подгрузке
фрагмента URL изменяется с помощью pushState, а нажатие
кнопки “Назад” восстанавливает предыдущий контент.
Можно контролировать кэширование с помощью опций cache и
stale:
up.render('/posts', { cache: 'reload' });
cache: 'reload' — всегда запрашивать свежие
данные.cache: 'prefer' — использовать кэш, если фрагмент уже
загружен.Unpoly легко интегрируется с серверными фреймворками, поддерживая стандартные маршруты и форматы ответа.
Пример ответа сервера:
<div up-target="main">
<h1><%= @post.title %></h1>
<p><%= @post.body %></p>
</div>
Важно возвращать HTML-фрагмент, соответствующий указанному
up-target. Если фреймворк возвращает JSON, необходимо
использовать up.render с обработкой ответа.
Unpoly позволяет загружать несколько фрагментов одновременно и управлять их приоритетом:
up.render({
'#sidebar': '/sidebar',
'#content': '/posts/42'
});
Это удобно для сложных страниц с несколькими зонами обновления.
При ошибках можно показать специальный фрагмент или выполнить перенаправление:
up.on('up:request:error', function(event) {
up.render('/errors/500', { target: '#main' });
});
Unpoly поддерживает серверную и клиентскую валидацию форм. Ошибки можно отображать в виде отдельных фрагментов:
<div id="form-errors" up-target="errors"></div>
<form action="/posts" method="post" up-target="main" up-error-target="#form-errors">
...
</form>
При ошибке сервер возвращает HTML для #form-errors, а
Unpoly автоматически вставляет его на страницу.
up-target для указания контейнера,
чтобы избежать непреднамеренного обновления всей страницы.up:fragment:loaded и
up:fragment:replaced для инициализации динамических
элементов после подгрузки.up-error-target для
аккуратного отображения ошибок, не перегружая основной контент.Unpoly объединяет преимущества классического многостраничного приложения и современных SPA, обеспечивая быструю, плавную работу интерфейса при минимальной сложности интеграции с серверной логикой.