NOTE: Apart from
(and even then it's questionable, I'm Scottish). These are machine translated in languages I don't read. If they're terrible please contact me.
You can see how this translation was done in this article.
Friday, 02 May 2025
//13 minute read
HTMX - це потужна бібліотека JavaScript, яка надає вам змогу створювати динамічні веб- програми з мінімальним рівнем JavaScript. За допомогою цього пункту ви зможете створювати запити AJAX, змінювати вміст HTML та обробляти події безпосередньо у ваших HTML атрибутах. Я використовую HTMX на даний момент близько двох років і з кожним проектом я дедалі більше дізнаюся про його можливості; і що важливіше, це обмеження.
Проте я все ще не стверджую, що маю про це знання експерта. Я лише хотів поділитися з вами тим, чого навчився.
Як ви бачите, у HTMX передбачено декілька подій, до яких ви можете прив' язатися для зміни запиту або відповіді. За допомогою кожної з них ви можете змінити спосіб, у який HTMX взаємодіє з сервером / клієнтом у досить комплексний спосіб.
Одним з найпотужніших аспектів HTMX є здатність до створити суфікси назв щоб розширити його можливості. У моєму випадку, я, як правило, в htmx:configRequest
щоб додати додаткові параметри до запиту. Цей пункт буде корисним, якщо ви бажаєте передати додаткові дані серверу без потреби в зміні коду HTML або JavaScript.
Інші суфікси можуть мати гачок htmx:beforeRequest
змінити запит перед надсиланням, але після більшість інших суфіксів, які з' єднують configRequest
; як в beforeRequest
елементи на зразок HX-Vals
і HX-Include
s вже прив' язано до лунки (або у рядку запиту\ query).
Ти можеш навіть гайнути. htmx:afterSwap
виконати дії після зміни вмісту. Комбіновано з клієнтськими бібліотеками на зразок Альпійський.js або Літ Ви можете створювати потужні динамічні програми з мінімальним кодом.
HTMX є вбудованими додатками на зразок hx-boost
і hx-swap-oob
За допомогою цього пункту ви зможете покращувати функціональні можливості HTMX без написання будь- якого нетипового коду. А втім, іноді потрібно створювати власні розширення, щоб відповідати певним вимогам.
Наприклад, у вас може виникнути потреба у додаванні нетипових заголовків до ваших запитів, зміні навантаження на запити або обробці окремих подій у унікальний спосіб.
Щоб досягти цього ГТМX, ви можете скористатися такими зручними точками інтеграції:
{
/**
* init(api)
* Called once when the extension is initialized.
* Use it to set up internal state, store references, or access HTMX utility functions via the api parameter.
*/
init: function(api) {
return null;
},
/**
* getSelectors()
* Returns additional CSS selectors that HTMX should monitor.
* Useful if your extension needs to handle custom elements or dynamic behavior.
*/
getSelectors: function() {
return null;
},
/**
* onEvent(name, evt)
* Called on every HTMX event (e.g., htmx:beforeRequest, htmx:afterSwap).
* Return false to cancel the event or stop propagation.
*/
onEvent: function(name, evt) {
return true;
},
/**
* transformResponse(text, xhr, elt)
* Modify the raw response text before it is parsed and swapped into the DOM.
* Use this to sanitize or preprocess HTML.
*/
transformResponse: function(text, xhr, elt) {
return text;
},
/**
* isInlineSwap(swapStyle)
* Return true if your extension will handle this swap style manually.
* This tells HTMX to skip default behavior.
*/
isInlineSwap: function(swapStyle) {
return false;
},
/**
* handleSwap(swapStyle, target, fragment, settleInfo)
* Perform custom DOM manipulation if you implement a custom swap style.
* Return true to prevent HTMX's default swap.
*/
handleSwap: function(swapStyle, target, fragment, settleInfo) {
return false;
},
/**
* encodeParameters(xhr, parameters, elt)
* Modify or serialize request parameters before sending.
* Return null to use default URL/form encoding.
* Return a string to override with a custom payload (e.g., JSON).
*/
encodeParameters: function(xhr, parameters, elt) {
return null;
}
}
HTMX - це декілька попередньо вбудованих додатків, які ви можете надати прочитати тут.
Наприклад, зручно вбудований суфікс json-encode
надає вам змогу надсилати дані JSON у тілі запиту замість даних форми, закодованих за адресою URL. Цей пункт буде корисним, якщо ви бажаєте надіслати на сервер складні структури даних або масиви.
Ви можете побачити, що цей гачок вміщується в 3 події
init
- для налаштування розширення і збереження посилання на API HTMXonEvent
- встановити Content-Type
заголовок до application/json
якщо запит налаштованоencodeParameters
- щоб перевизначити типове кодування форми, яке було закодовано за адресою URL, і перевизначити параметри як JSON. Крім того, програма повертає рядок, щоб запобігти використанню типового кодування форми HTMX за допомогою URL- encoded.(function() {
let api
htmx.defineExtension('json-enc', {
init: function(apiRef) {
api = apiRef
},
onEvent: function(name, evt) {
if (name === 'htmx:configRequest') {
evt.detail.headers['Content-Type'] = 'application/json'
}
},
encodeParameters: function(xhr, parameters, elt) {
xhr.overrideMimeType('text/json')
const object = {}
parameters.forEach(function(value, key) {
if (Object.hasOwn(object, key)) {
if (!Array.isArray(object[key])) {
object[key] = [object[key]]
}
object[key].push(value)
} else {
object[key] = value
}
})
const vals = api.getExpressionVars(elt)
Object.keys(object).forEach(function(key) {
// FormData encodes values as strings, restore hx-vals/hx-vars with their initial types
object[key] = Object.hasOwn(vals, key) ? vals[key] : object[key]
})
return (JSON.stringify(object))
}
})
})()
Або навіть простіше, але НАВІТЬ БІЛЬШЕ РУКИ hx-debug
суфікс, який додає HX-Debug
заголовок запиту. Цей пункт буде корисним для усування вад і ведення журналу, оскільки він надасть вам змогу переглядати дані щодо запиту та відповіді у консолі dev.
(function() {
htmx.defineExtension('debug', {
onEvent: function(name, evt) {
if (console.debug) {
console.debug(name, evt)
} else if (console) {
console.log('DEBUG:', name, evt)
} else {
throw new Error('NO CONSOLE SUPPORTED')
}
}
})
})()
Є багато більше, включаючи дуже потужну розширення інтерфейсу програми на стороні клієнта Це надає вам змогу використовувати клієнтські бібліотеки для перетворення даних JSON у HTML. Цей пункт буде корисним для створення динамічних UI без потреби покладатися на відображення на стороні сервера.
Наприклад, в нещодавньому проекті я використовував обмінки HTMX OOB для оновлення кількості рядків у таблиці. Щоб зробити це, я хотів знати, які рядки зараз показуються у таблиці, отже, я оновив лише видимі рядки.
export default {
encodeParameters: function (xhr, parameters, elt) {
const ext = elt.getAttribute('hx-ext') || '';
if (!ext.split(',').map(e => e.trim()).includes('dynamic-rowids')) {
return null; // Use default behavior
}
const id = elt.dataset.id;
const approve = elt.dataset.approve === 'true';
const minimal = elt.dataset.minimal === 'true';
const single = elt.dataset.single === 'true';
const target = elt.dataset.target;
const payload = { id, approve, minimal, single };
if (approve && target) {
const table = document.querySelector(target);
if (table) {
const rowIds = Array.from(table.querySelectorAll('tr[id^="row-"]'))
.map(row => row.id.replace('row-', ''));
payload.rowIds = rowIds;
}
}
// Merge payload into the parameters object
Object.assign(parameters, payload);
return null; // Return null to continue with default URL-encoded form encoding
}
}
Щоб використати його, нам потрібно додати розширення до нашої конфігурації HTMX. Отже, у вашому файлі, що вказує на js (якщо ви використовуєте модулі; йоу має бути) ви можете зробити щось на зразок цього:
import dynamicRowIds from "./dynamicRowIds"; // Load the file
htmx.defineExtension("dynamic-rowids", dynamicRowIds); // Register the extension
Потім, для будь-якого елементу, який ви хочете використати, ви можете додати hx-ext
атрибут зі значенням dynamic-rowids
.
<button
hx-ext="dynamic-rowids"
data-target="#my-table"
data-id="@Model.Id"
data-param1="true"
data-param2="false"
data-param3="@Model.Whatever"
hx-post
hx-controller="Contoller"
hx-action="Action"
>
<i class='bx bx-check text-xl text-white'></i>
</button>
Це ще одне просте розширення HTMX, на цей раз з'єднане з htmx:configRequest
тому що ми змінюємо URL перед надсиланням запиту. Цей додаток буде зручним, якщо ви використовуєте фільтрування, засноване на querystring тощо. і ви бажаєте, щоб деякі запити зберігали існуючі фільтри, а інші - ні (наприклад, " назва " і " startdate," але не " page " або " sort ").
Це SIMILAR, але не зовсім те саме, що існуюче розширення HTMX stop- params
Ви бачите, що ми гачок onEvent
слухати htmx:configRequest
Замечательно.
Тоді ми:
preserve-params-exclude
атрибут елемента (якщо такий існує) і поділено на масив ключів для виключення (отже, ми не додаємо їх до запиту)export default {
onEvent: function (name, evt) {
if (name !== 'htmx:configRequest') return;
const el = evt.detail.elt;
const excludeStr = el.getAttribute('preserve-params-exclude') || '';
const exclude = excludeStr.split(',').map(s => s.trim());
const currentParams = new URLSearchParams(window.location.search);
const newParams = new URLSearchParams(evt.detail.path.split('?')[1] || '');
currentParams.forEach((value, key) => {
if (!exclude.includes(key) && !newParams.has(key)) {
newParams.set(key, value);
}
});
evt.detail.path = evt.detail.path.split('?')[0] + '?' + newParams.toString();
return true;
}
};
Тут я використовую те, що необхідно HTMX.Net за помічниками з мітками. Любити hx-controller
і hx-action
є помічниками міток, які створюють правильні атрибути HTMX для вас. Так само, як і hx-route-<x>
значення, які слід передати у маршруті. Цей параметр дуже корисний, оскільки надає вам змогу використовувати код C# для створення правильних значень для атрибутів, а не для жорсткого кодування їх у HTML.
Бути розширенням, ним дуже просто користуватися:
Спочатку нам потрібно додати суфікс до нашої конфігурації HTMX.
import preserveParams from './preserveParams.js';
htmx.defineExtension('preserve-params', preserveParams);
ЗАУВАЖЕННЯ: ви помітите, що типові розширення HTMX використовують метод " автозавантаження " для завантаження додатка.
// Autoloading the extension and registering it
(function() {
htmx.defineExtension('debug', {
}
Це хороший спосіб зробити це, якщо використовувати HTMX у немодульному середовищі. Однак, якщо ви використовуєте модулі (якими ви повинні бути), краще використовувати import
оператор, який слід завантажити суфікс, а потім явно зареєструвати його на ваш комп' ютер htmx
Наприклад. За допомогою цього пункту ви зможете скористатися перевагами деревного покриття і завантажити лише потрібні суфікси.
Потім у вашому елементі ви можете додати hx-ext
атрибут зі значенням preserve-params
і preserve-params-exclude
атрибут з відокремленим комами списком параметрів, які виключать з запиту.
<a class="btn-outline-icon"
hx-controller="MyController"
hx-action="MyAction"
hx-route-myparam="@MyParam"
hx-push-url="true"
hx-ext="preserve-params"
preserve-params-exclude="page,sort"
hx-target="#page-content"
hx-swap="innerHTML show:top"
hx-indicator>
<i class="bx bx-search"></i>
</a>
У цьому випадку через event.detail.path
з новим myparam
значення, встановлене у цій змінній, замінить її на наше нове значення, але збереже всі інші (окрім page
і sort
). Таким чином, ми можемо передавати будь-які фільтри, які ми встановили в URL на сервер, не турбуючись, що вони втрачені, коли ми робимо новий запит.
Однією з акуратних особливостей HTMX є те, що більшість його взаємодії з сервером відбувається через заголовки HTTP. За допомогою цих заголовків ви можете вказати сервер з багатим контекстом даних, які було викликано запитом, що надасть вам змогу відповідно реагувати на ваші кінцеві пункти ядра ASP. NET або Razor.
Знову ключовим компонентом цього є HTMX.Net. Багато з них є охайними. Request
розширення для виявлення запитів HTMX. Цей пункт буде корисним для визначення того, чи було виконано запит HTMX, чи ні, і чи слід виконувати його відповідно.
Він також має власний механізм для передачі збудників.
Response.Htmx(h => {
h.WithTrigger("yes")
.WithTrigger("cool", timing: HtmxTriggerTiming.AfterSettle)
.WithTrigger("neat", new { valueForFrontEnd= 42, status= "Done!" }, timing: HtmxTriggerTiming.AfterSwap);
});
Натисніть Urls тощо... etc... Халід зробив чудову роботу, створюючи набір розширень, щоб було легше працювати з HTMX у ядрах ASP.NET.
Це ключовий інструмент у моїй панелі інструментів під час роботи з HTMX і ASP.NET Core. Заціни!
Тут йде спад найкорисніших заголовків, які HTMX надсилає з кожним проханням:
** ** _________________________________________________________________________________________________________________________________________. |----------------------------|------------------------------------------------------------------------------------------------------------------| ♪ HX-Request ♪ Завжди встановити значення true для будь-якого запиту на HTMX-initi. Чудово для виявлення сигналів HTMX у центральних програмах або контролерах. дрімати@ action: inmenu encoding of the bytes as values in the hexadecimal formats ♪ HX-Target ♪ [д] елементу цілі у DOM, на який буде повернуто відповідь. дрімати@ action: inmenu encoding of the bytes as values in the hexadecimal formats ♪ HX-Tr} id елемента, який викликав запит (e. g. кнопка). дрімати@ action: inmenu encoding of the bytes as values in the hexadecimal formats ♪ HX-Trgger-♪ Ім'я елементу, що викликає виклик (використовує форми). дрімати@ action: inmenu encoding of the bytes as values in the hexadecimal formats ♪ HX-Prompt}} використовує вхідні дані від hx-prompt. дрімати@ action: inmenu encoding of the bytes as values in the hexadecimal formats ♪ HX- Current-URL} URL навігатора, коли було висунуто запит. Корисно для ведення журналу та контексту. дрімати@ action: inmenu encoding of the bytes as values in the hexadecimal formats ♪ HX- History- Restorre-Request ♪♪ як true, якщо запит є частиною історичного відновлення після навігації (наприклад, кнопки backward). дрімати@ action: inmenu encoding of the bytes as values in the hexadecimal formats
Я використовую їх у своїх програмах ASPNET. Комбіновано з HTMX.Net, подібними до Request.IsHtmx()
, Request.IsHtmxBoosted()
і Request.IsHtmxNonBoosted()
ви легко можете визначити запити HTMX і відповідно відповісти на них.
Наприклад, у мене є дуже простий суфікс для запиту, за допомогою якого я можу визначити, чи не націлився мій головний запит. #page-content
Лови. Если это так, я знаю, что я должен отправлять назад частичный знак.
ЗАУВАЖЕННЯ: багато хто не розуміє, що можна вказати частинну " повну сторінку," а потім просто пропустити компонування.
if (Request.PageContentTarget())
{
Response.PushUrl(Request);
return PartialView("List", vm);
}
return View("List", vm);
public static class RequestExtensions
{
public static bool PageContentTarget(this HttpRequest request)
{
bool isPageContentTarget = request.Headers.TryGetValue("hx-target", out var pageContentHeader)
&& pageContentHeader == "page-content";
return isPageContentTarget;
}
}
Окрім суфіксів запиту, ви також можете створити розширення відповіді для надсилання записів подій до клієнта. Цей пункт буде корисним для запуску подій зі сторони клієнта.
Наприклад, в моїй інтеграції SweetAlert2 Увімкнути закриття діалогового вікна за допомогою перемикача, який встановлено на сервері.
document.body.addEventListener('sweetalert:close', closeSweetAlertLoader);
Ця дія активується з сервера як подія- перемикач HTMX.
public static void CloseSweetAlert(this HttpResponse response)
{
response.Headers.Append("HX-Trigger" , JsonSerializer.Serialize(new
{
sweetalert = "close"
}));
}
За допомогою цього пункту можна увімкнути sweetalert:close
подія на стороні клієнта, за допомогою якої ви можете закрити діалогове вікно. Крім того, ви можете передавати дані клієнту за допомогою команди HX-Trigger
заголовок. Цей пункт буде корисним для передавання даних з сервера на клієнт без потреби у зміні коду HTML або JavaScript.
Як бачите, дуже легко слухати ці події, просто додаючи до тіла слухача події. Я використовую JSON в основному, як він завжди кодується належним чином.
Раніше я писав про свій метод тостів. тутАле варто згадати і про це. Дуже просто увімкнути сервер для вмикання сповіщення про тост на стороні клієнта. Я встановив гачок у цьому розширенні відповіді.
public static void ShowToast(this HttpResponse response, string message, bool success = true)
{
response.Headers.Append("HX-Trigger", JsonSerializer.Serialize(new
{
showToast = new
{
toast = message,
issuccess =success
}
}));
}
Потім я зв'язуюся з клієнтом події і дзвоню showToast
функція.
import { showToast, showHTMXToast } from './toast';
window.showHTMXToast = showHTMXToast;
document.body.addEventListener("showToast", showHTMXToast);
Це кличе мене. showToast
function і well, показує тост; знову ж таки, щоб дізнатися більше про це у статті .
export function showHTMXToast(event) {
const xhr = event?.detail?.xhr;
let type = 'success';
let message = xhr?.responseText || 'Done!';
try {
const data = xhr ? JSON.parse(xhr.responseText) : event.detail;
if (data.toast) message = data.toast;
if ('issuccess' in data) {
type = data.issuccess === false ? 'error' : 'success';
} else if (xhr?.status >= 400) {
type = 'error';
} else if (xhr?.status >= 300) {
type = 'warning';
}
} catch {
if (xhr?.status >= 400) type = 'error';
else if (xhr?.status >= 300) type = 'warning';
}
showToast(message, 3000, type);
}
Ну ось і все, вихор на HTMX і ASPNET Core. Сподіваюся, вона вам дуже корисна і інформативна. Якщо у вас є якісь запитання або коментарі, будь ласка, прокоментуйте їх нижче.