HTMX med ASP
Inleiding
Om du har byggt traditionella ASP, ., NET Core MVC-applikationer och , vet du vad problemet är. att känna modern.
Tekniken att återfå partiella HTML-fragment från servern och byta dem till DOM löser detta - och det är inte nytt' . Jag har använt det här mönstret sedan jQuerys dagar, , och även innan det med vanilla JavaScript och XMLHttpRequest. Vad elegant det' blir med HTMX
HTMX ger oss ett deklarativt sätt att göra det vi alltid gjort.', :, servern tillbaka.-, HTML som skickas fram och omvandlas till sidan.
Kompanionsartikel: Den här artikeln fokuserar på ASP-integrationen. En vissel Tour över HTMX-extensioner och hur man använder HT MX med ASP.NET Core.
I den här artikeln kommer jag att visa hur HTMX integreras vackert med ASP HTMX.NET bibliotek gör det ännu bättre mostlylucid.pagingtaghelper NuGet paketet använder HTMX och erbjuder kraftfull webbing med minimal konfiguration.
Ansatsen är framework, -, och också agnostisk. Django lade fram szablonfragment i versionen. Rails har Turborammar, ,, och det bredare web-ekosystemet omfamnar HTML.
Vad är HTMX?
HTMX är en bibliotek som låter dig få tillgång till moderna webblärafunktioner direkt från HTML, snarare än att skriva JavaScript. Det utvidger HTML med attribut som tillåter dig att göra AJAX- begäran , byta innehållet , och skapa rika interaktioner M SK4 allt utan att lämna ditt märke
De viktigaste attributen du kommer att använda
hx-get,hx-post,hx-put,hx-delete- Gör HTTP- begäranhx-target- Specifiera var svaret ska placerashx-swap- Kontrollera hur innehållet skiftas innerHTML, outerHTML, etchx-trigger- Definiera vad som utlöser begäran. klick, , förändring,, ladda,,, etc.hx-push-url- uppdatera webbläsarens URL utan att ladda upp hela sidan igen
Här är "'". Det är skönheten med det. : , du, ' , skriver fortfarande servern. - , sidakod, M SK4 , återvänder servern, - , skickar HTML.
Ett mönster lika gammalt som AJAX själv
Innan HTMX, uppnådde vi samma effekt med betydligt fler ceremonier . Här' är hur partiella uppdaterade händelser såg ut i jQuery- eran
// jQuery circa 2010
$('#load-more').click(function() {
$.ajax({
url: '/posts/page/' + currentPage,
success: function(html) {
$('#posts-container').append(html);
currentPage++;
}
});
});
Och ännu tidigare, med vanilla JavaScript
// Vanilla JS circa 2005
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
document.getElementById('content').innerHTML = xhr.responseText;
}
};
xhr.open('GET', '/partial-content', true);
xhr.send();
Servern- var identisk med dess sida-mönster ♫ - ♫ återfå HTML fragment ♫ , ♫ byter dem till DOM ♫. ♫ HTMX flyttar bara den här logiken från JavaScript till HTML-attribute ♫ , ♫ gör det deklarativt ♫, ♫ upptäckbar ♫ Sk6 ♫ och långt mindre fel ♫ sk7 ♫ antaglig ♫ SMk8 ♫ Innovationen är inte ♫ ' ♫ tekniken ♫ Smk10 ♫ utan ♫ smk11 ♫ gränssnittet ♫
ASP.NET-utvecklare har gjort detta i åratal PartialView() i MVC sedan dag ett, Html.RenderAction() för sammankommningsbara fragment - möjligheten har alltid funnits där . Vad vi saknade var en elegant, standardiserad sätt att koppla upp den på kundensidanM SK3 HTMX fyller den klyftan perfektMSC4
Den bredare industrin har också återupptäckt dessa mönster.. Begrepp som: ", SSR, " och ( Server, -, sida- Rendering, Mska5, Mske6, hybrid- rendering, M Ska7 och Mska8, ISLANDs arkitektur, M ska9, beskriver i grunden vad server, M SK10, sida ramverk alltid har gjort.,, men med nya ögon.
Att installera HTMX i ASP.NET Core
Först, inkludera HTMX i din layout. Du kan använda en CDN eller servera den lokalt
<script src="https://unpkg.com/[email protected]"></script>
Det är det.
Alpine.js
För klienten- sida-reaktivitet ( att visa / gömda element| ,| radande tillstånd| ,| lokalt gränssnittステetet Alpine.js kompletterar HTMX perfekt
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
Här är hur de arbetar tillsammans.
<div x-data="{ open: false }">
<button x-on:click="open = !open">Toggle</button>
<div x-show="open" x-transition>
<button hx-get="/api/data" hx-target="#results">Load Data</button>
</div>
</div>
Alpine hanterar den lokala gränssnittet (, att byta, HTMX hanterar serveruppdrag, (, datalämpningen, )., Under hela artikeln, M SK4, ser du detta mönster. ♫ -, Alpine för klientreaktiviteter, MSC7, Htmx för serverinteraktioner,
Biblioteket HTMX.NET
Khalid Abuhakmeh's HTMX.NET bibliotek tillhandahåller den första ASP-klassen, - Htmx och Htmx.TagHelpers NuGet packages, känns inhemskt till .NET och gör det till ett absolut nöje att jobba med HTMX. GitHub.
Installation
dotnet add package Htmx
dotnet add package Htmx.TagHelpers
I din _ViewImports.cshtml:
@addTagHelper *, Htmx.TagHelpers
IsHtmx() Erweiterungsmetoden
Det mest användbara är Request.IsHtmx() förlängningsmetoden, som säger till dig om begäran kom från HTMX
[HttpGet]
public async Task<IActionResult> Index(int page = 1, int pageSize = 20)
{
var posts = await blogViewService.GetPagedPosts(page, pageSize);
if (Request.IsHtmx())
return PartialView("_BlogSummaryList", posts);
return View("Index", posts);
}
Detta mönster är absolut lysande. En enda kontrollaktion fungerar för båda
- Hela sidan laddas ( när användare navigerar direkt eller uppdaterar
- Litegranna uppdaterade versioner ( när HTMX gör begäran)
Inga separata API- slutpunkter , inga duplicerade logiker, ingen JSON serialisering överhuvudtaget
Ett vanligt missuppfattning: Många ASP.NET-utvecklare tror att du behöver
_prefix (lik_BlogSummaryList.cshtml) för att få en partiell rendering . Du gör intePartialView()metoden själv säger till ASP.NET Core att hoppa över layouten - det ' som säger ♫ " glöm layoutet ♫return PartialView("SearchResults", model)med en vanlig bildfiler och det fungerar perfekt. underscore-konventionen uppstod från ASP.NET webbsidor (WebMatrixM SK3 där den förhindrade att archive serverades direkt via URL MSC4 men MVC har alltid skyddat alla bilder från direkt tillgång hursomhelst avsedda som delar.
HTMX.NET Etikettbekymmer
HTMX.NET erbjuder tagbekymmer som gör att arbetet med kontroller är renare . Istället för att skriva ut spårsträngar , kan du använda starkt
<button
hx-controller="Comment"
hx-action="GetCommentForm"
hx-post
hx-target="#commentform">
Reply
</button>
Detta genererar den korrekta vägen med hjälp av ASP.NET Core'riktningssystemet
Här är ett verkligt exempel från den här bloggen
<button
class="btn btn-outline btn-sm mb-4"
hx-action="Comment"
hx-controller="Comment"
hx-post
hx-vals
x-on:click.prevent="window.mostlylucid.comments.setValues($event)"
hx-on="htmx:afterSwap: window.scrollTo({top: 0, behavior: 'smooth'})"
hx-swap="outerHTML"
hx-target="#commentform">
Comment
</button>
Titta på hur HTMX spelar fint med Alpine.js (x-on:click.prevent) för de då och dåliga bitarna av klienten- sidainteraktivitetM SK2
Andra HTMX.NET hjälparbetare
Biblioteket erbjuder också
Request.IsHtmxNonBoosted()- Kolla om det är en HTMX- begäran men inte upphöjtRequest.IsHtmxRefresh()- Kolla om det är en historia återställelse begäran- Redaktions hjälpmedel för HTMX-kolor ( triglar , redirectioner, etcM SK3
Verklig-World Example: söka med delar
Här är sökreglern från den här bloggen.
[HttpGet]
[OutputCache(Duration = 3600, VaryByHeaderNames = new[] { "hx-request", "pagerequest" })]
public async Task<IActionResult> Search(
string? query,
int page = 1,
int pageSize = 10,
[FromHeader] bool pagerequest = false)
{
var searchModel = await BuildSearchModel(query, page, pageSize);
if (pagerequest && Request.IsHtmx())
return PartialView("_SearchResultsPartial", searchModel.SearchResults);
if (Request.IsHtmx())
return PartialView("SearchResults", searchModel);
return View("SearchResults", searchModel);
}
Tre återvändsvägar för tre scenarior:
- Seitenupplägg - minimalt delaktigt | ( | bara listan av resultat |)
- Filterförändringar - sektioner delaktiga | ( | resultat med filter |)
- Direktnavigation - hela sidan
Det delaktiga synsättet (_SearchResultsPartial.cshtml) använder tagassistenten
@model Mostlylucid.Models.Blog.PostListViewModel
<div class="pt-2" id="content">
@if (Model.Data?.Any() is true)
{
<div class="inline-flex w-full items-center justify-center pb-4">
@if (Model.TotalItems > Model.PageSize)
{
<pager
x-ref="pager"
link-url="@Model.LinkUrl"
hx-boost="true"
hx-target="#content"
hx-swap="show:none"
page="@Model.Page"
page-size="@Model.PageSize"
total-items="@Model.TotalItems"
hx-headers='{"pagerequest": "true"}'>
</pager>
}
</div>
@foreach (var post in Model.Data)
{
<partial name="_ListPost" model="post"/>
}
}
</div>
Att bryta ner pagertag hjälparen:
hx-boost="true"- Intercepterar länkar , konverterar till AJAXhx-target="#content"- Var man ska injicera reaktionenhx-headers='{"pagerequest": "true"}'- Custom-Header säger till kontrollören att det är 's pagination- Controllern kontrollerar
Request.IsHtmx() && pagerequestför att återfå bara den minimala deldelen
Det mest tydliga packaget.pagingtaghelper
Jag skrev mostlylucid.pagingtaghelper för att undvika repetitiv pagination kod. Det's HTMXMSC2first men fungerar utan JavaScript ocksåM SK3
Installation
dotnet add package mostlylucid.pagingtaghelper
Lägg till _ViewImports.cshtml:
@addTagHelper *, mostlylucid.pagingtaghelper
Nyckliga egenskaper
Implementera IPagingModel<T> och du
public class BasePagingModel<T> : IPagingModel<T> where T : class
{
public int Page { get; set; }
public int TotalItems { get; set; }
public int PageSize { get; set; }
public string LinkUrl { get; set; }
public List<T> Data { get; set; }
}
Vad får du:
- Null konfiguration krävs
- Flera gränssnitt (TailwindCSS | + | DaisyUI | , | Bootstrap | 5, | custom views
- Dark mode support
- 8 språk byggde
- Sortierbara opskrifte, sidans storlekslekar
- Fortskridande förbättring ( fungerar utan JavaScript
- Fortsättningstoken-stöd för NoSQL-databaser
Etiketteassistenten genererar länkar som bevarar söksträngar, stödjer räätällig nagłówk, och integrerar genomskärt med HTMX ( se exemplet ovanförM SK3
HTMX-flödesdiagramm
Här är hur hela systemet passar ihop.
graph TB
A[Browser] -->|"Initial page load"| B[Controller Action]
B -->|"Request.IsHtmx() = false"| C[Return Full View]
C --> D[Render Layout + Partial]
A -->|"User clicks pagination/filter"| E[HTMX Request]
E -->|"hx-get with headers"| F[Same Controller Action]
F -->|"Request.IsHtmx() = true"| G{Check Headers}
G -->|"pagerequest header"| H[Return Minimal Partial]
G -->|"No special header"| I[Return Section Partial]
H --> J[Swap Content in Target]
I --> J
J -->|"User clicks another link"| E
style B stroke:#333,stroke-width:2px
style F stroke:#333,stroke-width:2px
style C stroke:#0066cc,stroke-width:2px
style H stroke:#00cc66,stroke-width:2px
style I stroke:#00cc66,stroke-width:2px
jämförelse med andra ramverk
Django-templatefragment
Django lade till med rätt delversions-template-rendering i versionen 6.0 (December | 2024) | med templatefragmenter |. | Innan det ♫ , ♫ använde Django utvecklare vanligtvis inkluderande tag eller tredjedelar ♫ PartialView() sedan versionen 1.0 i ♫ 2016 ♫ ♫ МSK2 ♫ olika ramverk ♫ , ♫ flera tidsramar ♫ m, ♫ men samma destination ♫ M: ♫ HTML fragment för HTMX ♫
Rörlar Turborammar
Ruby on Rails har turboramar ( en del av Hotwire), som är lik i själenM SK2
<%= turbo_frame_tag "posts" do %>
<%= render @posts %>
<% end %>
Skillnaden är att Turbo kräver specifika rammarkörer både på begäran och på svaren. hx-target.
Phoenix LiveView
Elixir's Phoenix LiveView tar ett annat tillvägagångssätt med bestående WebSocket-kopplingar och server
def handle_event("load_more", _params, socket) do
{:noreply, assign(socket, posts: load_more_posts())}
end
LiveView är lysande för riktiga applikationer.
Tillvägagångspunkter
Input Caching: Den OutputCache attribut varierar med hx-request header, kakande av hela sidor och delar separat
[OutputCache(Duration = 3600, VaryByHeaderNames = new[] { "hx-request", "pagerequest" })]
nätverkseffektivitet: Server
Bundle-storlek: HTMX (14KB) | | + | optional Alpine | . | js | {\displaystyle |} (15 | Kb | МSK6 | _ |+ | pgging tag helper | (eng.) (0 | kb ♫ , | server | [eng.] - | sida | LMB 11 | lMB 12 | under 30 | Total | Łäng |
avancerade mönster
Optimistiska gränssnittuppdateringar - Kombinera HTMX och Alpine för direkt återkoppling
<div x-data="{ count: @Model.CommentCount }">
<button hx-post="/comment/like" x-on:click="count++" hx-on::after-request="count = $event.detail.xhr.response">
Likes: <span x-text="count"></span>
</button>
</div>
Beräkningen uppdateras omedelbart (optimistiskt ), och sinkroniseras sedan med serveruppkopplingen
Utan bandsvapningar - uppdatera flera sidor från ett svar
<div id="main-content"><!-- Main response --></div>
<div id="notification-count" hx-swap-oob="true"><span>5 new</span></div>
Perfekt för budskapsblöcke, Körkolor , etc. Jag täcker detta mönster djupt i Att visa bröd och bytes med HTMX.
Client-Side-template med WebAPI - Ibland vill du ha en mellantids- -upplevelse med : servern, -- -som ger HTML för de flesta sakerna, ,- -men JSON från ett WebAPI för specifik dynamisk innehåll. klient-sidan-templates förlängning låter dig göra exakt detta
<script src="https://unpkg.com/[email protected]/client-side-templates.js"></script>
<script src="https://unpkg.com/mustache@latest"></script>
<div hx-ext="client-side-templates">
<template id="post-template" type="text/mustache">
{{#posts}}
<div class="post">
<h3>{{title}}</h3>
<p>{{excerpt}}</p>
</div>
{{/posts}}
</template>
<button hx-get="/api/posts"
hx-target="#post-list"
mustache-template="post-template">
Load Posts
</button>
<div id="post-list"></div>
</div>
Den här tillvägagångssätten fungerar med Mustache, Handlebars, eller Nunjucks-templater . Din WebAPI återskapar JSONM SK3 men HTMX hanterarレンereringsclientetMska4 sidaM Ska5 DetMske6 är särskilt användbart när du har en fungerande API eller behöver dela med dig av data med mobila appsMka7 För mer information om HT MX-extensioner inklusive klient, se den medföljande artikeln.
Gotchas & Tips
Debugging-verktyg: Installera HTMX-debuggerextension - den visar varje begäran , respons , och utbyter i realtid
CSRF-tokens
ASP.NET Core's antifalsifierade token behöver särskild handling med AJAXM SK2 HTMX .NET erbjuder flera rena alternativ HtmxAntiforgeryScriptEndpoint:
// In Program.cs
app.MapHtmxAntiforgeryScript();
<!-- In your layout head -->
<script src="@HtmxAntiforgeryScriptEndpoints.Path" defer></script>
Eller använda tagassistenten: <meta name="htmx-config" includeAspNetAntiforgeryToken="true" />. Se Khalid's artikel om HTMX Anti--–Fälgeriska tokens för mer information.
Alpine.js @ Korthand i racer
Alpine's @click korthand konflikter med Razor's @ syntax. Använd det explicita systemet istället:
<button x-on:click="doSomething()">Click me</button> <!-- Instead of @click -->
<div x-bind:class="isOpen ? 'block' : 'hidden'"></div> <!-- Instead of :class -->
Eller fly med @@click, men explicit syntax är tydligare
Historiska avdelningar
Kontrollerande historiainträg: Standardmässigt, trycker HTMX varje begäran till historien . För paginationer / filtrerar där du inte vill att historien ska förorenas
<paging model="@Model" hx-push-url="false"> <!-- Don't add history entries -->
Eller använda hx-replace-url="true" att uppdatera URL: s utan att lägga till insatser.
Det Phantompartiella problemet: Browser bakåt/ framåt visar bara en delfragment utan layout. Fixera med hx-history-elt på din innehållsbehållare:
<div class="container mx-auto" id="contentcontainer" hx-history-elt>
@RenderBody()
</div>
Det talar om för HTMX vilket element att ta fram i ett ögonblick, och bevara omgivningen när man återställer historien
CDN Caching (Cloudflare
Symptom: HTMX fungerar lokalt men bryter sig bakom en CDN - fel innehåll får kasserad
Root Cause: CDN ignorerar HX-Request header. Din server återskapar olika innehåll baserat på den här headern, men CDN kastar dem identiskt.
ASP.NET Core fix Använda VaryByHeaderNames:
[OutputCache(Duration = 3600, VaryByHeaderNames = new[] { "hx-request" })]
CDN fix: Konfigurera kasregler för att inkludera HX-Request i kask nyckeln. För Cloudflare: Tappbord → Caching | → | Kaskregler |→ | Passformskask nyckel ♫ → | Header ♫ HX-Request.
Debatten om hx-
hx-boost omvandlar normala länkar till AJAX- begäran. Den HTMX-Quirks-sida noterar att några grundteammedlemmar rekommenderar att undvika det (löser <head> innehåll, påverkar lokalitet i beteendet), medan andra tycker att det är bra för snabba vinster
<div hx-boost="true" hx-target="#contentcontainer">
<a asp-action="Show" asp-route-slug="@post.Slug">Read More</a>
</div>
Denna blogg använder den i stor utsträckning. När det är riktat mot specifika behållare hx-get är tydligare, men hx-boost fungerar om du hx-boost="false" på barnelementen.
Slutsatsen
HTMX med ASP.NET Corepartiklar representerar en återkomst till servern
- Dynamiska, SPA-liknande interaktioner
- Server-Seiten rendering (trevlig för SEOM SK2
- Passande HTTP-キャッシュing
- Minimal JavaScript
- Fortskridande förbättring
- Typ-säkra routering med HTMX.NET
- Zero-config pagination med mostlylucid.pagingtaghelper
Servern, -, har klarat testet av tiden, och med HTMX,,, har den till slut den eleganta klienten som den förtjänar.-, med hjälp av verktygen som det förtövar. ., du kan bygga robusta webapplikationer med flera årtionden fungerande mönster.
Related Articles on This Blog
Kompanionsartikel
Detta artikel är en del av en serie med två delar på HTMX med ASP
- Denna artikel - fokuserar på ASP. Net Core integrering , partiell syn på , HTMX
- En vissel-stoppturning av HTMX-extensioner - djupt dyka in i HTMX-eventen , livscykeln , utbyggnadsarkitekturen
Fler HTMX-artiklar
- Att lägga till webbningar med HTMX - Den ursprungliga artikeln om att implementera pagination med den äldre PaginationTagHelper
- ASP.Net Core Caching med HTMX - djupt dyka in i kasseringsstrategier för HTMX-behov
- Auto-refresh med Alpine och HTMX - kombinerar Alpine.js med HTMX för reaktiva komponenter
- Att göra din sida mer SPA-liknande med HTMX - SPA-liknande navigation utan JavaScript ramverk
- Att använda SweetAlert för HX indikatorer - vackra ladeindikatorer med HTMX
- Att visa bröd och bytes med HTMX - Server
Fortsättning avläsning
officiella dokumentation:
- HTMX Dokumentation - Den officiella HTMX-dokumentationen
- HTMX exempel - Praktiska exempel på HTMX-mönster
- HTMX-extensioner - De officiella HTMX-extensionerna
- Alpine.js Dokumentation - officiella Alpine-docks
- Alpine.js exempel - Praktiska alpska mönster
- ASP.NET Kernpartiella synpunkter - Microsofts guide to partial views
- ASP.Net Core Output Caching - Den officiella kaskande dokumentationen
Bibliotek & verktyg:
- HTMX.NET GitHub - Bibliotekets källkod
- HTMX.NET NuGet - HTMX.NET på NuGet
- Htmx.TagHelpers NuGet - HTMX Tag Helpers på NuGet
- Khalid Abuhakmehs hemsida - Uppfinnaren av HTMX.NET , med utmärkta bloggar
- Khalid Abuhakmeh på GitHub - Mer fantastiska öppna projekt
- mostlylucid.pagingtaghelper GitHub - My paging tag helper source code
- mostlylucid.pagingtaghelper NuGet - Paketet på NuGet
Samhällens resurser:
- HTMX-diskord - Aktivt samhällsstöd
- HTMX Essays - Tankfulla artiklar om HTMX-filosofi
- Hypermediasystembok - Gratis online bok om att bygga hypermediaapplikationer