Частичные рендеры

Unpoly — это библиотека для прогрессивного улучшения веб-приложений, позволяющая обновлять только части страницы без полной перезагрузки. Ключевая концепция — частичный рендер (partial rendering), при котором сервер возвращает HTML-фрагмент, который заменяет или дополняет существующую разметку на клиенте. Это ускоряет интерфейс, снижает нагрузку на сервер и обеспечивает плавный пользовательский опыт.


Селекторы и целевые элементы

В Unpoly обновление происходит по селекторам, задающим контейнеры, которые будут заменены. Например:

<div id="content">
  <p>Старое содержимое</p>
</div>

<a href="/new_content" up-target="#content">Обновить</a>
  • up-target — атрибут, указывающий, какой элемент DOM будет обновлён.
  • Если up-target не задан, Unpoly пытается определить контейнер автоматически по совпадению селектора <body> или <main>.

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


Стратегии замены содержимого

Unpoly поддерживает несколько способов вставки новых фрагментов:

  1. replace (по умолчанию) — заменяет существующий контейнер полностью.

  2. insert — добавляет контент внутрь контейнера:

    • up-insert="before" — вставляет перед контейнером.
    • up-insert="after" — вставляет после контейнера.
    • up-insert="top" — вставляет в начало контейнера.
    • up-insert="bottom" — вставляет в конец контейнера.
  3. remove — удаляет контейнер после успешного ответа сервера.

Пример вставки в конец списка:

<ul id="messages">
</ul>

<a href="/new_message" up-target="#messages" up-insert="bottom">Добавить сообщение</a>

Обработка серверного ответа

Сервер может возвращать:

  • Полный HTML-контейнер: <div id="content">...</div>. Unpoly заменяет контейнер полностью.
  • Фрагмент без контейнера: <p>Новый текст</p>. Тогда контейнер, указанный в up-target, остаётся, а фрагмент вставляется внутрь согласно стратегии up-insert.

Для корректной работы важно, чтобы сервер возвращал HTML, валидный и семантически согласованный с текущей структурой DOM.


Атрибуты для частичного рендеринга

Помимо up-target и up-insert есть другие важные атрибуты:

  • up-transition — задаёт анимацию замены содержимого:

    <div id="content" up-transition="fade">...</div>

    Поддерживаются эффекты: fade, slide, cross-fade, а также кастомные CSS-классы.

  • up-swap — определяет, как именно вставляется новый контент (replace, after, before, prepend, append).

  • up-on-success / up-on-error — позволяют выполнять JS-функции после успешного или неудачного рендера.

  • up-confirm — выводит диалог подтверждения перед запросом:

    <a href="/delete_item" up-target="#item" up-confirm="Вы уверены?">Удалить</a>

Вложенные и повторяющиеся частичные рендеры

Unpoly поддерживает множественные частичные обновления одновременно:

<a href="/update" up-target="#content1,#content2">Обновить оба блока</a>
  • Все указанные селекторы будут обновлены одной серверной отдачей.

  • Сервер может возвращать несколько контейнеров одновременно:

    <div id="content1">...</div>
    <div id="content2">...</div>

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


Формы и частичный рендер

Формы в Unpoly обрабатываются с поддержкой AJAX по умолчанию:

<form action="/update_form" method="post" up-target="#form-container">
  <input type="text" name="name">
  <button type="submit">Сохранить</button>
</form>
  • После отправки сервер возвращает HTML-фрагмент для #form-container.
  • Можно использовать up-validate="true" для автоматической валидации и отображения ошибок без перезагрузки.

Также формы поддерживают замену кнопок и полей по селекторам через атрибут up-target на отдельных элементах формы.


Программное обновление через API

Unpoly предоставляет JS-API для динамического частичного рендеринга:

up.replace('#content', '/new_content');
up.append('#messages', '<li>Новое сообщение</li>');

Основные методы:

  • up.replace(target, urlOrHtml) — заменяет контейнер.
  • up.append(target, content) / up.prepend(target, content) — добавляет контент.
  • up.remove(target) — удаляет элементы.
  • up.insertAfter(target, content) / up.insertBefore(target, content) — вставляет рядом с контейнером.

Методы позволяют гибко интегрировать Unpoly с динамическими компонентами и сторонними библиотеками.


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

Unpoly автоматически обновляет историю браузера при частичных рендерах:

  • Атрибут up-history="false" отключает запись:

    <a href="/new_content" up-target="#content" up-history="false">Обновить без истории</a>
  • Можно задавать заголовок страницы через up-title:

    <div up-title="Новый заголовок">...</div>
  • История корректно работает с кнопками «Назад» и «Вперёд», повторно вызывая частичные рендеры без перезагрузки страницы.


Ошибки и отладка

Частичные рендеры могут не сработать из-за:

  • Неправильного селектора в up-target.
  • Отсутствия соответствующего контейнера в ответе сервера.
  • Некорректного HTML (например, незакрытые теги).
  • Конфликтов с JavaScript, который удаляет контейнер до завершения рендера.

Для отладки полезны встроенные события Unpoly:

document.addEventListener('up:fragment:loaded', event => {
  console.log('Фрагмент загружен:', event.target);
});
  • up:fragment:loaded — вызывается после вставки нового контента.
  • up:fragment:loading — перед отправкой запроса.
  • up:fragment:failed — при ошибке сервера.

Практические рекомендации

  • Разделять страницу на логические контейнеры, чтобы минимизировать пересылку лишнего HTML.
  • Использовать уникальные ID или классы для up-target, избегая селекторов по тегам.
  • Для форм применять up-validate и up-on-success для удобного UX.
  • Анимации через up-transition делают интерфейс плавным, но не должны блокировать пользовательские действия.
  • Сложные страницы можно строить на комбинации replace, append и вложенных рендеров для максимальной динамичности.

Частичные рендеры в Unpoly позволяют создавать интерактивные веб-приложения с минимальной нагрузкой и плавным пользовательским опытом, комбинируя простые HTML-фрагменты, селекторы и JS-API.