Back to "Успілковий тур по HTMX розширенням та використанню HT MX з ASP.NET Core"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

ASP.NET Core HTMX Javascript

Успілковий тур по HTMX розширенням та використанню HT MX з ASP.NET Core

Friday, 02 May 2025

Введение

HTMX - це потужна JavaScript-лібература, яка дозволяє створювати динамічні веб-приложения з мінімальним JavaScriptом. Вона дає вам змогу робити AJAX-запити , обмінюватися HTML-контентом МSK2 і обробляти події безпосередньо в ваших HTML-атрибутах. ЯM SK4 я користуюсь HT MX приблизно два роки на даний момент, і з кожним проектом я дізнаюся все більше і більше про його можливості M SK5 і, що важливіше, про обмеження цього '

Однак я досі не вважаю, що маю на це експертні знання. Я просто хотів поділитися деякими речами, які я вивчив на шляху.

Article: Ця стаття зфокусується на системі подій HTMX' МSK1 розширеннях , та заawansowanej налаштуваннях . Для ASPM SK4 NET Конкретні моделі інтеграції з частинними видами HTMX з ASP.NET Core Partials: ServerM SK2Side Renaissance.

Мероприяти

Підготування запиту

Фаза підготовки запиту - це те місце, де HTMX налаштовує запит перед тим, як він відправляється до сервера.. Це включає в себе налаштування заголовків.

flowchart LR

        A[htmx:configRequest] --> B[htmx:confirm] --> C[htmx:prompt] --> D[htmx:abort]

Вимагати життєвого циклу

Фаза життєвого циклу запитів - це те місце, де HTMX надсилає запит до сервера і відповідає на нього.

flowchart LR
 E[htmx:beforeRequest] --> F[htmx:request] --> G[htmx:afterRequest]

Керування відповіддю

Фаза управління відповіддю - це те, коли HTMX обробляє реакцію з сервера і оновлює DOM. Під час цієї фазы тригуються наступні події

flowchart LR
        H[htmx:beforeOnLoad] --> I[htmx:onLoad]
        I --> J[htmx:beforeSwap] --> K[htmx:swap] --> L[htmx:afterSwap]
        L --> M[htmx:afterSettle] --> N[htmx:afterOnLoad]

Керування історією

Фаза управління історією - це те місце, де HTMX оновлює історію браузера та URL. Під час цієї фазы тригуються наступні подіїM SK1

flowchart LR
 A[htmx:historyRestoreRequest]
 A --> B[htmx:historyPopped]
 B --> C[htmx:historyRestorePage]

Як ви бачите, HTMX надає безліч подій, до яких можна під 'єднатися для зміни запиту чи відповіді, або навіть історіїM SK1 HT MX робить LOT для того, щоб бути такою компактною системою . Використовуючи кожен з них, ви можете змінити те, як HTX взаємодіє з сервером

Поширення

Одним із найпотужніших аспектів HTMX є можливість створити розширення розширити свої можливості. У моєму випадку htmx:configRequest для додавання додаткових параметрів до запиту. Це корисно, коли ви хочете передати додаткові дані до сервера, не modyfikуючи код HTML або JavaScript

Інші розширення можуть під 'єднатися htmx:beforeRequest до того, як запрос буде відправлений;, але після більшість інших розширень, які configRequest; як у beforeRequest такі речі, як HX-Vals і HX-Includes вже прикріплені до найпершого ( або в payload МSK1 querystringM SK2 Ви можете навіть підключитися htmx:afterSwap для виконання дій після заміни контенту. Об 'єднаний з комп' ютерними бібліотеками, такими як Alpine.js або Літ ви можете створювати потужні динамічні додатки з мінімальним кодом.

HTMX надає деякі вбудовані rozszerzenia, такі як - hx-boost і hx-swap-oob які дають змогу покращити функцію HTMX без написання будь-якого спеціального коду. Тим не менш

Наприклад:, ви можете додати за замовчанням заголовки до ваших запитів , змінити плату за подачу запиту МSK2 або обробляти певні події у унікальний спосіб

Щоб досягнути цього, HTMX надає вам певні вручні точки інтеграції:


{
  /**
   * 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 надає низку збудованих przed- розширення, які можна читайте про це тут.

Наприклад, гарний збудовано- в розширенні json-encode дозволяє надсилати дані JSON в корпусі запиту замість URL-encoded form dataM SK1 Це корисно, коли ви хочете надіслати складні структури чи массиви даних до сервера Ви бачите, що це пов 'язано з подіями 3

  • init - для налаштування розширення і зберігання посилання до API HTMX
  • onEvent - для набору Content-Type заголовок до application/json коли запрос конфігурований
  • encodeParameters - перемикає початковий URL - кодування зашифрованої форми і серіалізує параметри як JSON МSK2 Він також повертає строк, щоб запобігти тому, що HTMX не використовуватиме початкового URL
(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))
    }
  })
})()

Або навіть простіший, але ще HANDY 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')
      }
    }
  })
})()

Є ще багато таких, як МСК0 і МСК1, включно з дуже потужним clients side templating extension що дозволяє вам використовувати клієнтові-side templating библиотеки для перетворення отриманих даних JSON в HTML . Це корисно для створення динамічних інтерфейсів без необхідності покладатися на сервер-side renderingM SK3

Деякі налаштування

Цифрові ID динамічних рядів

Наприклад, у нещодавньому проекті я використовував swapи HTMX OOB для оновлення рядків в таблиці. Для цього я хотів знати, які рядки зараз відображаються в таблиці,, тож я обновив лише ті рядки, які були помітніM SK1

Поширення

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 перед тим, як відправити уривок запросуM SK1 Це розширення дуже зручно, якщо ви' використовуєте пошуковий строк на основі фильтрації і т.д. . і хочете, щоб деякі уривки зберігали існуючі фильтры, тоді як інші - не.

Це СIMILAR, але не зовсім те ж саме, що і теперішнє розширення HTMX push-params

Поширення

Ви бачите, що ми onEvent щоб слухати htmx:configRequest події.

Тоді ми:

  • Візьміть елемент, який спричинив подію
  • Візьміть preserve-params-exclude атрибут з елементу ( якщо він існуєM SK1 і розділити його на сукупність ключів, щоб виключити
  • Візьміть поточні параметри URL з локації вікна
  • Візьміть нові параметри з URL запиту
  • Прокрутить поточні параметри і перевірити, чи вони не є в списку виключення та не є вже в нових параметрах
  • Якщо вони не є,, ми додаємо їх до нових параметрів
  • Врешті-решт, ми встановили нові параметри для URL запиту і повертаємо true, щоб продовжити роботу з запитомM SK1
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> для wartości, що проходить в маршруті. Це дійсно корисно, адже ви можете використовувати код C#, щоб генерувати правильні значення для атрибутів, замість того, щоб hardcode їх у вашому HTML

Використовуючи

Будучи розширенням, це дуже просто використовувати

По-перше, треба додати до нашої HTMX конфігурації rozszerzenie.


import preserveParams from './preserveParams.js';
htmx.defineExtension('preserve-params', preserveParams);

NOTA: ВиM SK1 помітите, що стандартні rozszerzenia HTMX використовують метод 'автозавантаження ' для завантаження rozszerzenia

// Autoloading the extension and registering it
(function() {
  htmx.defineExtension('debug', {
}

Це хороший спосіб зробити це, якщо ви' використовуєте HTMX в не-модульному середовищі -, а(M SK2). Тим не менше,, якщо ви (МSK4) використовуєте модулі (, які ви маєте використовувати(МSK6), то краще використовувати import твердження для завантаження rozszerzenia, а потім явно записувати його проти вашого htmx instance. Це дозволяє вам скористатися перевагами дерева -shaking і завантажувати лише необхідні розширення

Тоді на вашому елементі ви можете додати 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 значення встановити його в ньому' замінюватиме це одним нашим новим значенням, але зберегти всі інші M SK1за винятком page і sort). Таким чином, ми можемо далі передавати на сервер будь-які відфільтри, які ми встановили в URL, не переживаючи про їх втрату, коли ми робимо новий запит

ASP.NET Кора

Однією з найцікавіших речей про HTMX є те, що велика частина його взаємодії з сервером відбувається через HTTP заголовки. Ці заголовка забезпечують сервером багатим контекстом того, що викликало запрошення ,, що дозволяє вам адекватно реагувати від вашого ASP МSK2 NET Коренные кінцеві точки або погляди Razor .

Знову ж таки, ключовою складовою є HTMX.Net. Серед багатьох речей, які він надає, є непомітні Request розширення для виявлення HTTP-запросів. Це корисно для визначення, чи подан HTMX запрос, чи ні , і для його відповідного виконання

Він також має власний механізм для відправлення триггерів


Response.Htmx(h => {
    h.WithTrigger("yes")
     .WithTrigger("cool", timing: HtmxTriggerTiming.AfterSettle)
     .WithTrigger("neat", new { valueForFrontEnd= 42, status= "Done!" }, timing: HtmxTriggerTiming.AfterSwap);
});

Приштовхування Urls і т.д....etcM SK1 Халід зробив чудову роботу, створивши низку поширень, щоб було легше працювати з HTMX в ASP

Це ключеві інструменти в моєму наборі інструментів, коли я працюю з HTMX та ASP. Подивіться на це.

Поширені заголовки запитів HTMX

Ось список найпотрібніших заголовків, які HTMX надсилає з кожним запитом.

Заголовок МSK1 Описание МSK2
HXM SK1Рейкція Завжди вмикається на правильне для будь-якого HTMX-initiated requestMska4 Чудово для виявлення HT MX дзвінків у середній програмі чи контроллерахM Ska5 Мska6
HXM SK1Target Идентификаційний номер елементу в DOM, в якому відповідь буде замінена на
HXM SK1 Триггер Идентификатор елементу, який триграв запити МSK3eMSC4g. кнопка МSK6 |
HXM SK1 Триггер-Назви Назва триггерного елементу
HXM SK1Prompt Составляє вхід користувача з hx-promptMSC4 МSK5
HXM SK1На даний момент-URL Веб-браузер URL, коли запрос був започаткований
HX -HistoryM SK2Restore-Request МSK4 Отримають правильну відповідь, якщо ця просьба є частиною відновлення історії після навігації.

Запроси про розширення

Я користуюся цим досить широко в своїх програмах ASP.NET Core. Поєднані з такими, як HTMXM SK2Net Request.IsHtmx() , Request.IsHtmxBoosted() і Request.IsHtmxNonBoosted() ви можете легко розпізнати HTTPMX запити і відповісти відповідно.

Наприклад, У мене є дуже простий додаток до Request, який дозволяє мені виявити, чи запити спрямовані на мою головну #page-content div. Якщо це так, то я знаю, що повинен відіслати назад частину NOTA: Багато хто не усвідомлює, що ви можете ввести M SK2повну сторінку ' як частину МSK4 і тоді просто перекидає макет

        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;
    }
    }

Поширення реагування

Окрім розширення Request,, ви також можете створити Response extensions для відсилання подій назад до клієнта

Наприклад, SweetAlert

Наприклад, в моєму інтегруванні 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 події з боку клієнта,, що дозволяє закрити диалогM SK1 Дані можна передати назад клієнту за допомогою HX-Trigger заголовок. Це корисно для передачі даних від сервера до клієнта, не modyfikуючи код HTML чи JavaScriptM SK1

Як ви бачите, МСК0 легко слухати ці події, просто додавши до тіла слухача подій. МSK1 Я користуюся JSON, бо він завжди правильно кодує.

Подивіться

Раніше я писав про свій тост тут, але це також варто згадати ' так само як і тут МSK2 Для того, щоб дуже просто дозволити серверу триггерувати paziņoння про тост з боку клієнта \ . \ Я встановив тригнер у цьому розширенні Відповіді

    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 функція і добре, показує тостM SK1 знову погляньте на це більше у статті .



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 та ASP-сервіс. Я сподіваюся, що ви зрозуміли, що це дуже корисно і цікаве.

Подібні статті в цьому блогі

Article Companion

Ця стаття є частиною серії двох частин на HTMX з ASP

  1. HTMX з ядром ASP.NET - зосереджена на ASPM SK1 NET Коренная інтеграція , частинні переглядиМSK3 HTMX.NETMSC5 та відображання
  2. Цей artykuł - Глубокий занурення в події HTMX , життєвий цикл МSK2 архітектура rozszerzenia

Більше статей про HTMX

Дальне читання

офіційна документація HTMX:

Бібліотеки & НаrzędziаM SK1

Community Resources:

logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.