Что нового в htmx 4
Исчерпывающий перечень всех изменений в htmx 4.0.
Несовместимые изменения
fetch() заменяет XMLHttpRequest
Все запросы используют нативный API fetch(). Это нельзя отменить.
Явное наследование
Добавьте :inherited к любому атрибуту, который должен наследоваться вниз по дереву DOM.
<!-- htmx 2: implicit inheritance -->
<div hx-confirm="Are you sure?">
<button hx-delete="/item/1">Delete</button>
</div>
<!-- htmx 4: explicit inheritance -->
<div hx-confirm:inherited="Are you sure?">
<button hx-delete="/item/1">Delete</button>
</div> Работает с любым атрибутом: hx-boost:inherited, hx-target:inherited, hx-confirm:inherited и т. д.
Используйте :append, чтобы добавить значение к наследуемому, а не заменить его:
<div hx-include:inherited="#global-fields">
<!-- appends .extra to the inherited value -->
<form hx-include:inherited:append=".extra">...</form>
</div> Вернуть прежнее поведение: htmx.config.implicitInheritance = true
Подмена ответов с ошибками
htmx 4 подменяет содержимое при получении всех HTTP-ответов. Подмена не выполняется только для 204 и 304.
В htmx 2 ответы 4xx и 5xx не подменялись. В htmx 4, если сервер возвращает HTML с кодом 422 или 500, этот HTML подставляется в целевой элемент. Создавайте ответы с ошибками так, чтобы их HTML можно было использовать для подмены, или используйте hx-status, чтобы задать поведение для отдельных кодов.
Вернуть прежнее поведение: htmx.config.noSwap = [204, 304, '4xx', '5xx']
hx-delete не включает данные формы
Как и hx-get, hx-delete больше не включает поля родительской формы.
Исправление: при необходимости добавьте hx-include="closest form".
Без кэширования истории
История больше не кэширует страницы в localStorage. При переходе назад htmx повторно загружает страницу и подменяет содержимое в <body> или, если он присутствует, в элементе [hx-history-elt]. Поведение такое же, как в htmx 2.
Используйте htmx.config.history = "reload", чтобы вместо этого полностью перезагрузить страницу. Используйте htmx.config.history = false, чтобы отключить эту возможность.
Порядок внеполосной подмены
В htmx 2 элементы для внеполосной подмены (hx-swap-oob) подменялись до основного содержимого.
В htmx 4 сначала подменяется основное содержимое. Элементы для внеполосной подмены и <hx-partial> подменяются после него (в порядке следования в документе).
Это важно, если при внеполосной подмене создаются или изменяются элементы DOM, от которых зависит основная подмена. Если приложение зависит от такого порядка, измените его структуру так, чтобы каждая подмена была независимой.
Модификатор hx-trigger queue удалён
Модификатор queue атрибута hx-trigger (например, hx-trigger="click queue:all") больше не работает. Постановка запросов в очередь теперь управляется исключительно атрибутом hx-sync.
<!-- htmx 2 --> <div hx-trigger="click queue:all" hx-get="/test">...</div> <!-- htmx 4: use hx-sync instead --> <div hx-trigger="click" hx-get="/test" hx-sync="this:queue all">...</div>
Тайм-аут 60 секунд
В htmx 2 тайм-аута не было (0). В htmx 4 параметру defaultTimeout задано значение 60000.
Вернуть прежнее поведение: htmx.config.defaultTimeout = 0
Загрузка расширений
Подключайте скрипты расширений напрямую. Атрибут не нужен:
<script src="/path/to/htmx.js"></script> <script src="/path/to/ext/sse.js"></script>
Ограничьте список расширений, которые могут загружаться:
<meta name="htmx-config" content='{"extensions": "sse, ws"}'> Авторы расширений используют htmx.registerExtension(name, methodMap) для регистрации.
Подробнее см. в разделе Система расширений.
Переименования и удаления
Атрибуты
Выполните переименование hx-disable до обновления. В htmx 2 hx-disable означал «не обрабатывать этот элемент средствами htmx». В htmx 4 для этого используется hx-ignore, а hx-disable теперь выполняет функцию, которую раньше выполнял hx-disabled-elt.
| htmx 2.x | htmx 4.x | Тип | Примечания |
|---|---|---|---|
hx-disable |
hx-ignore |
переименован | Сначала переименуйте этот атрибут, чтобы избежать конфликтов. |
hx-disabled-elt |
hx-disable |
переименован | Переименуйте этот атрибут после того, как hx-disable станет hx-ignore. |
hx-vars |
hx-vals |
удалён | Используйте префикс js:. |
hx-params |
htmx:config:request |
удалён | Настройте параметры запроса в событии. |
hx-prompt |
расширение hx-prompt |
удалён | Также можно использовать однострочный код с hx-on. |
hx-ext |
— | удалён | Подключайте скрипты расширений напрямую. |
hx-disinherit |
— | удалён | Не нужен. Наследование задаётся явно. |
hx-inherit |
— | удалён | Не нужен. Наследование задаётся явно. |
hx-request |
hx-config |
удалён | — |
hx-history |
— | удалён | Без localStorage. |
События
Все события теперь следуют новому шаблону: htmx:phase:action[:sub-action]. Большинство событий ошибок объединены в htmx:error. Для HTTP-ответов с ошибками используется htmx:response:error.
| htmx 2.x | htmx 4.x | Тип | Примечания |
|---|---|---|---|
htmx:afterOnLoad |
htmx:after:init |
переименовано | — |
htmx:afterProcessNode |
htmx:after:init |
переименовано | — |
htmx:afterRequest |
htmx:after:request |
переименовано | — |
htmx:afterSettle |
htmx:after:settle |
переименовано | — |
htmx:afterSwap |
htmx:after:swap |
переименовано | — |
htmx:beforeCleanupElement |
htmx:before:cleanup |
переименовано | — |
htmx:beforeHistorySave |
htmx:before:history:update |
переименовано | — |
htmx:beforeOnLoad |
htmx:before:init |
переименовано | — |
htmx:beforeProcessNode |
htmx:before:process |
переименовано | — |
htmx:beforeRequest |
htmx:before:request |
переименовано | — |
htmx:beforeSwap |
htmx:before:swap |
переименовано | — |
htmx:configRequest |
htmx:config:request |
переименовано | — |
htmx:historyCacheMiss |
htmx:before:history:restore |
переименовано | — |
htmx:historyRestore |
htmx:before:history:restore |
переименовано | — |
htmx:load |
htmx:after:init |
переименовано | — |
htmx:oobAfterSwap |
htmx:after:swap |
переименовано | — |
htmx:oobBeforeSwap |
htmx:before:swap |
переименовано | — |
htmx:pushedIntoHistory |
htmx:after:history:push |
переименовано | — |
htmx:replacedInHistory |
htmx:after:history:replace |
переименовано | — |
htmx:responseError |
htmx:response:error |
переименовано | Для HTTP-ответов с ошибками используется это событие. |
htmx:sendError |
htmx:error |
переименовано | — |
htmx:swapError |
htmx:error |
переименовано | — |
htmx:targetError |
htmx:error |
переименовано | — |
htmx:timeout |
htmx:error |
переименовано | — |
htmx:validation:validate |
— | удалено | Используйте встроенную проверку форм браузером. |
htmx:validation:failed |
— | удалено | Используйте встроенную проверку форм браузером. |
htmx:validation:halted |
— | удалено | Используйте встроенную проверку форм браузером. |
htmx:xhr:loadstart |
— | удалено | Теперь htmx использует fetch(). |
htmx:xhr:loadend |
htmx:finally:request |
удалено | Теперь htmx использует fetch(). |
htmx:xhr:progress |
— | удалено | Теперь htmx использует fetch(). |
htmx:xhr:abort |
htmx:error |
удалено | Теперь htmx использует fetch(). |
Конфигурация
| htmx 2.x | htmx 4.x | Тип | Примечания |
|---|---|---|---|
defaultSwapStyle |
defaultSwap |
переименовано | — |
globalViewTransitions |
transitions |
переименовано | — |
historyEnabled |
history |
переименовано | — |
includeIndicatorStyles |
includeIndicatorCSS |
переименовано | — |
timeout |
defaultTimeout |
переименовано | — |
defaultTimeout |
60000 |
значение по умолчанию изменено | Раньше было 0 (тайм-аута не было). |
defaultSettleDelay |
1 |
значение по умолчанию изменено | Раньше было 20. |
addedClass |
— | удалено | CSS-класс htmx-added по-прежнему применяется во время подмены. |
allowEval |
— | удалено | — |
allowNestedOobSwaps |
— | удалено | — |
allowScriptTags |
— | удалено | — |
attributesToSettle |
— | удалено | — |
defaultSwapDelay |
— | удалено | — |
disableSelector |
hx-ignore |
удалено | — |
getCacheBusterParam |
— | удалено | — |
historyCacheSize |
— | удалено | — |
ignoreTitle |
— | удалено | По-прежнему работает для каждой подмены через hx-swap="... ignoreTitle:true". |
inlineStyleNonce |
— | удалено | Для CSS индикатора теперь используются конструируемые таблицы стилей, поэтому nonce не нужен. |
methodsThatUseUrlParams |
— | удалено | — |
refreshOnHistoryMiss |
— | удалено | — |
responseHandling |
hx-status |
удалено | Используйте вместе с noSwap. |
scrollBehavior |
— | удалено | — |
scrollIntoViewOnBoost |
— | удалено | — |
selfRequestsOnly |
htmx.config.mode |
удалено | — |
settlingClass |
— | удалено | CSS-класс htmx-settling по-прежнему применяется во время подмены. |
swappingClass |
— | удалено | CSS-класс htmx-swapping по-прежнему применяется во время подмены. |
triggerSpecsCache |
— | удалено | — |
useTemplateFragments |
— | удалено | — |
withCredentials |
hx-config |
удалено | — |
wsBinaryType |
— | удалено | — |
wsReconnectDelay |
— | удалено | — |
Заголовки запросов
| htmx 2.x | htmx 4.x | Тип | Примечания |
|---|---|---|---|
HX-Trigger |
HX-Source |
изменён формат | Формат: tagName#id, например button#submit. |
HX-Target |
HX-Target |
изменён формат | Формат: tagName#id. |
HX-Trigger-Name |
HX-Source |
удалён | — |
HX-Prompt |
расширение hx-prompt |
восстановлен расширением | Загрузите расширение. |
| — | HX-Request-Type |
новый |
"full" или "partial". |
| — | Accept |
новый | Основные запросы отправляют text/html; hx-sse добавляет text/event-stream. |
Заголовки ответов
| htmx 2.x | htmx 4.x | Тип | Примечания |
|---|---|---|---|
HX-Trigger-After-Swap |
HX-Trigger |
удалён | Также можно использовать JavaScript. |
HX-Trigger-After-Settle |
HX-Trigger |
удалён | Также можно использовать JavaScript. |
HX-Trigger |
HX-Trigger |
без изменений | — |
HX-Location |
HX-Location |
без изменений | — |
HX-Push-Url |
HX-Push-Url |
без изменений | — |
HX-Redirect |
HX-Redirect |
без изменений | — |
HX-Refresh |
HX-Refresh |
без изменений | — |
HX-Replace-Url |
HX-Replace-Url |
без изменений | — |
HX-Retarget |
HX-Retarget |
без изменений | — |
HX-Reswap |
HX-Reswap |
без изменений | — |
HX-Reselect |
HX-Reselect |
без изменений | — |
JavaScript API
| htmx 2.x | htmx 4.x | Тип | Примечания |
|---|---|---|---|
htmx.addClass() |
element.classList.add() |
удалён | Используйте нативный JavaScript. |
htmx.removeClass() |
element.classList.remove() |
удалён | Используйте нативный JavaScript. |
htmx.toggleClass() |
element.classList.toggle() |
удалён | Используйте нативный JavaScript. |
htmx.closest() |
element.closest() |
удалён | Используйте нативный JavaScript. |
htmx.remove() |
element.remove() |
удалён | Используйте нативный JavaScript. |
htmx.off() |
removeEventListener() |
удалён |
htmx.on() возвращает функцию обратного вызова. |
htmx.location() |
htmx.ajax() |
удалён | — |
htmx.defineExtension() |
htmx.registerExtension() |
переименован | — |
htmx.logAll() |
htmx.config.logAll = true |
удалён | htmx выполняет запись в журнал через console.*. |
htmx.logNone() |
— | удалён | — |
htmx.logger |
console.* |
удалён | Инструменты наблюдаемости перехватывают console.error, console.warn и console.log. |
htmx.onLoad() |
htmx.onLoad() |
изменён | Теперь прослушивает htmx:after:process, а не htmx:after:init. |
По-прежнему доступны: htmx.ajax(), htmx.config, htmx.find(), htmx.findAll(), htmx.on(), htmx.onLoad(), htmx.parseInterval(), htmx.process(), htmx.swap(), htmx.trigger().
Что нового
Атрибуты
| Атрибут | Назначение |
|---|---|
hx-action |
Указать URL с необязательным hx-method. Поддерживает постепенное улучшение с помощью нативного резервного варианта action/method |
hx-method |
Указать HTTP-метод (переопределяет нативные method и formmethod) |
hx-query |
Выполнить запрос QUERY, который передаёт параметры в теле запроса |
hx-config |
Настройка запроса для отдельного элемента (JSON или синтаксис key:value) |
hx-ignore |
Отключить обработку htmx (ранее hx-disable) |
hx-validate |
Управлять поведением проверки формы |
Модификаторы прокрутки hx-swap
Модификаторы show и scroll больше не поддерживают комбинированный синтаксис selector:position. Вместо этого используйте отдельные ключи:
<!-- htmx 2 (broken in 4) --> <div hx-swap="innerHTML show:#other:top"></div> <!-- htmx 4 --> <div hx-swap="innerHTML show:top showTarget:#other"></div> <div hx-swap="innerHTML scroll:bottom scrollTarget:#other"></div>
Стили hx-swap
<div hx-get="/data" hx-swap="innerMorph">...</div> <div hx-get="/data" hx-swap="outerMorph">...</div> <div hx-get="/text" hx-swap="textContent">...</div> <div hx-get="/remove" hx-swap="delete">...</div>
-
innerMorph/outerMorph: подмена с морфингом с использованием алгоритма idiomorph. Лучше подходит для сохранения состояния в сложных интерфейсах. -
textContent: установить текстовое содержимое целевого элемента (без разбора HTML). -
delete: полностью удалить целевой элемент.
Новые псевдонимы существующих стилей подмены (работают как старые, так и новые названия):
| Новое название | Эквивалент |
|---|---|
before |
beforebegin |
after |
afterend |
prepend |
afterbegin |
append |
beforeend |
Подмены по коду состояния
Задайте разное поведение подмены для каждого кода состояния HTTP:
<form hx-post="/save"
hx-status:422="swap:innerHTML target:#errors select:#validation-errors"
hx-status:5xx="swap:none push:false">
<!-- form fields -->
</form> Доступные ключи конфигурации: swap:, target:, select:, push:, replace:, transition:.
Поддерживаются точные коды (404), подстановочные символы для одной цифры (50x) и подстановочные символы для диапазонов (5xx). Проверка выполняется в порядке убывания специфичности.
<hx-partial>
Нацеливайте ответ на несколько элементов. Альтернатива hx-swap-oob для случаев, когда требуется явно управлять выбором целевых элементов и стратегией подмены:
<hx-partial hx-target="#messages" hx-swap="beforeend">
<div>New message</div>
</hx-partial>
<hx-partial hx-target="#count">
<span>5</span>
</hx-partial> Каждый <hx-partial> задаёт собственную стратегию hx-target и hx-swap. Полную документацию см. в разделе Обновления нескольких целевых элементов.
Переходы между представлениями
Поддержка API переходов между представлениями доступна, но по умолчанию отключена.
Включить: htmx.config.transitions = true
Совместимость с JSX
Во фреймворках, не поддерживающих : в именах атрибутов, можно использовать metaCharacter, чтобы заменить его:
htmx.config.metaCharacter = "-"; // hx-ws-connect instead of hx-ws:connect // hx-confirm-inherited instead of hx-confirm:inherited
Методы JavaScript
-
htmx.timeout(time): возвращает промис, который разрешается по истечении задержки (число миллисекунд или строка интервала'500ms'/'1s'/'5m')
htmx.takeClass удалён из ядра. Аналогичные возможности предоставляет расширение hx-live в пространстве имён htmx.live:
htmx.live.take(target, className, source) // strip class from `source`, add to `target` htmx.live.forEvent(...args) // race events/timeouts htmx.live.nextFrame() // promise that resolves on next animation frame htmx.live.q(selector) // jQuery-like proxy rooted at documentElement htmx.live.debounce(ms[, fn]) // global debounce htmx.live.refresh() // recompute every live expression
В области видимости выражений hx-live/hx-on они доступны без префикса (take, forEvent, nextFrame, q, debounce, toggle); в качестве неявного контекста используется текущий элемент. См. документацию расширения hx-live.
Автоматически регистрируемые события
События, инициированные внутри библиотеки, выводятся в консоль следующим образом:
- Если для события задано
detail.error, вывод направляется вconsole.error(если применимо, экземпляр Error сначала выводится целиком, чтобы DevTools отобразил стек вызовов). Сюда относятся сбои запросов, исключения в обработчиках hx-on и другие случаи выбрасывания исключений. Приложения, подписанные наhtmx:error, получают те же данные через событие. - Если задано
detail.warn, вывод направляется вconsole.warn. - В противном случае событие записывается на уровне
console.log(по умолчанию сообщения не отображаются; задайтеhtmx.config.logAll = true, чтобы показывать их).
Это восстанавливает соглашение htmx 2.x: чтобы внутренний сбой отображался в консоли, отправьте событие с detail.error (или detail.warn); настройка console.error для каждого сайта не требуется.
Контекст запроса в событиях
Все события предоставляют согласованный объект ctx с информацией о запросе и ответе.
События
| Событие | Когда происходит |
|---|---|
htmx:after:cleanup |
После очистки элемента |
htmx:after:history:update |
После обновления истории |
htmx:after:process |
После обработки элемента |
htmx:before:response |
Перед чтением тела ответа (можно отменить) |
htmx:before:settle |
Перед этапом фиксации |
htmx:after:settle |
После этапа фиксации |
htmx:before:viewTransition |
Перед началом перехода между представлениями |
htmx:after:viewTransition |
После завершения перехода между представлениями |
htmx:finally:request |
При завершении, сбое или отмене запроса |
Ключи конфигурации
| Параметр | Значение по умолчанию | Назначение |
|---|---|---|
extensions |
'' |
Список разрешённых имён расширений, разделённых запятыми |
mode |
'same-origin' |
Режим Fetch (заменяет selfRequestsOnly) |
inlineScriptNonce |
'' |
Nonce для встроенных скриптов |
metaCharacter |
':' |
Символ-разделитель в именах атрибутов и событий |
morphIgnore |
["data-htmx-powered"] |
Префиксы имён атрибутов, сохраняемые при морфинге |
morphScanLimit |
Максимальное число элементов для сканирования при сопоставлении в ходе морфинга | |
morphSkip |
'[hx-morph-skip]' |
CSS-селектор элементов, которые нужно пропускать при морфинге |
morphSkipChildren |
'[hx-morph-skip-children]' |
CSS-селектор элементов, дочерние элементы которых нужно пропускать при морфинге |
Основные расширения
Теперь htmx 4 поставляется с множеством «основных» расширений. Расширения SSE и WebSocket были значительно переработаны, а hx-multipart, hx-live, hx-targets, hx-ptag, hx-csp, hx-download, hx-prompt и hx-history-cache — новые. Подробности см. в руководствах по обновлению для этих расширений.
| Расширение | Категория | Описание |
|---|---|---|
hx-multipart |
Потоковая передача HTML | Потоковая передача HTML с помощью multipart/mixed
|
hx-sse |
Потоковая передача HTML | Потоковая передача HTML с помощью text/event-stream (SSE) (руководство по обновлению) |
hx-ws |
Потоковая передача HTML | Потоковая передача HTML и отправка данных через WebSocket (руководство по обновлению) |
hx-browser-indicator |
Удобство использования | Показывать индикатор загрузки вкладки с помощью hx-browser-indicator
|
hx-live |
Удобство использования | Наше собственное решение для реактивных скриптов на основе DOM |
hx-pending |
Удобство использования | Показывать пользовательское содержимое во время выполнения запросов |
hx-prompt |
Удобство использования | Запрашивать подтверждение перед запросами с помощью hx-prompt='Reason?'
|
hx-preload |
Производительность | Предварительная загрузка при наведении курсора (руководство по обновлению) |
hx-history-cache |
Производительность | Восстанавливать страницы при переходе назад/вперёд из sessionStorage
|
hx-ptag |
Производительность | Пропускать неизменившиеся опросы с помощью HX-PTag: "v42"
|
hx-download |
Подмены | Скачивать файлы с помощью hx-swap='download'
|
hx-head |
Подмены | Объединять теги <head> с помощью hx-head='merge'
|
hx-targets |
Подмены | Нацеливать на множество элементов с помощью hx-targets='.selector'
|
hx-upsert |
Подмены | Обновлять или добавлять элементы с помощью hx-swap='upsert'
|
htmx-2-compat |
Совместимость | Восстанавливает значения по умолчанию и имена событий htmx 2.x в htmx 4 |
hx-alpine-compat |
Совместимость | Запускает htmx вместе с Alpine.js без конфликтов |
hx-csp |
Безопасность | Обеспечивает работу htmx при строгой политике безопасности содержимого |
Licensed under the Zero-Clause BSD License.
https://four.htmx.org/docs/whats-new-in-htmx-4/