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
In questo sito uso HTMX ampiamente, questo è un modo super facile per rendere il vostro sito sentire più reattivo e più liscia senza dover scrivere un sacco di JavaScript.
NOTA: Non sono ancora del tutto soddisfatto di questo, HTMX ha alcuni elementi che rendono questo difficile
Utilizzando HTMX con ASP.NET Core è un po 'di un sogno, Ho scritto su questo in precedenza in questo post. E 'davvero abbastanza facile 'HTMXify' il tuo sito, ed è un ottimo modo per rendere il vostro sito sentire più reattivo.
Come parte del mio ultimo andare in giro utilizzando HTMX ho deciso di fare il maggior numero di collegamenti su questo sito utilizzare HTMX come possibile. Quindi, ad esempio, se si fa clic sul pulsante 'Home' sopra di esso ora utilizza HTMX per caricare il contenuto della pagina.
Questo lo raggiungo semplicemente aggiungendo alcune proprietà al link tag, come questo:
<a asp-action="IndexPartial" asp-controller="Home" hx-swap="show:window:top" hx-target="#contentcontainer" hx-boost="true" class="mr-auto sm:mr-6">
<div class="svg-container">
<img src="/img/logo.svg" asp-append-version="true" width="180px" height="30px" alt="logo" :class="{ 'img-filter-dark': isDarkMode }"/>
</div>
</a>
Qui potete vedere che aggiungo il hx-swap
attributo, questo dice a HTMX di scambiare il contenuto dell'elemento di destinazione con il contenuto restituito dal server.
NOTA: NON usare hx-pushurl in quanto questo farà sì che il browser per ricaricare la pagina sul backbutton due volte.
La hx-target
attributo indica a HTMX dove mettere il contenuto restituito dal server. In questo caso è il #contentcontainer
elemento (dove viene caricato tutto il contenuto della pagina).
Aggiungo anche: hx-swap="show:window:top
che rende la finestra scorrere verso l'inizio della pagina quando il contenuto viene scambiato.
La parte C# di questo è abbastanza semplice, semplicemente duplica il mio normale metodo Index ma invece carica la vista parziale. Il codice è mostrato di seguito. Ancora una volta questo usa HTMX.NET per rilevare la hx-request
intestazione e restituire la vista parziale. C'è anche un cut-out per restituire la vista normale se la richiesta non è una richiesta HTMX.
[Route("/IndexPartial")]
[OutputCache(Duration = 3600, VaryByHeaderNames = new[] { "hx-request" })]
[ResponseCache(Duration = 300, VaryByHeader = "hx-request",
Location = ResponseCacheLocation.Any)]
[HttpGet]
public async Task<IActionResult> IndexPartial()
{
ViewBag.Title = "mostlylucid";
if(!Request.IsHtmx()) return RedirectToAction("Index");
var authenticateResult = await GetUserInfo();
var posts = await BlogService.GetPagedPosts(1, 5);
posts.LinkUrl = Url.Action("Index", "Home");
var indexPageViewModel = new IndexPageViewModel
{
Posts = posts, Authenticated = authenticateResult.LoggedIn, Name = authenticateResult.Name,
AvatarUrl = authenticateResult.AvatarUrl
};
return PartialView("_HomePartial", indexPageViewModel);
}
Il risultato è che questo link (e altri utilizzando la stessa tecnica) carica come 'AJAX' richieste e il contenuto viene scambiato senza una pagina completa ricaricare. Questo evita il fastidioso 'chiaro flash' si ottiene quando una pagina si ricarica a causa di come funziona il mio scambio di tema.
Quindi il metodo qui sotto può essere fatto funzionare comunque è super complicato e un po 'imbarazzante.
A HTMX piace molto lavorare usando l'approccio basato sugli attributi. Uso htmx.ajax
è tipo del metodo'se tutto il resto fallisce' e significa che è necessario incasinare con la storia borwser.
Purtroppo la cronologia del browser usando pushState
replaceState
e popstate
è davvero un po 'di un dolore al collo (ma può essere super potente per i casi di bordo).
Invece quello che sto facendo ora è solo aggiungere hx-boost
al tag che contiene il contenuto del blog.
<div class="prose prose max-w-none border-b py-2 text-black dark:prose-dark sm:py-2" hx-boost="true" hx-target="#contentcontainer">
@Html.Raw(Model.HtmlContent)
</div>
Questo sembra funzionare bene come hx-boost
possono essere inseriti sui metodi genitori e si applicano a tutti i collegamenti bambini. E 'anche più standard HTMX senza scherzare con la storia ecc.
Nella rara occasione che non si desidera utilizzare HTMX per particolari collegamenti è possibile aggiungere hx-boost="false"
al collegamento.
Tuttavia un problema con questo approccio è stato il mio blog link come questo: HTMX per un'esperienza simile alla SPA che non sono collegamenti "normali." Questi collegamenti sono generati dal parser markdown; mentre posso scrivere un'estensione MarkDig per aggiungere gli attributi HTMX ai collegamenti, ho deciso di usare un approccio diverso (perché ho già una tonnellata di contenuti che non voglio riparlare).
Invece ho aggiunto una funzione JavaScript che cerca tutti questi tipi di link, quindi utilizza htmx.ajax
per fare lo scambio. Questo è essenzialmente ciò che HTMX fa comunque solo'manuale'.
Come si può vedere questa è solo una semplice funzione che cerca tutti i link nel div.prose
elemento che inizia con un /
e poi aggiunge un ascoltatore di eventi a loro. Quando il collegamento è cliccato l'evento è impedito, l'URL viene estratto e quindi il htmx.ajax
funzione è chiamata con l'URL e l'elemento di destinazione da aggiornare.
(function(window) {
window.blogswitcher =() => {
const blogLinks = document.querySelectorAll('div.prose a[href^="/"]');
// Iterate through all the selected blog links
blogLinks.forEach(link => {
link.addEventListener('click', function(event) {
event.preventDefault();
let link = event.currentTarget;
let url = link.href;
htmx.ajax('get', url, {
target: '#contentcontainer', // The container to update
swap: 'innerHTML', // Replace the content inside the target
}).then(function() {
history.pushState(null, '', url);
window.scrollTo({
top: 0,
behavior: 'smooth' // For a smooth scrolling effect
});
});
});
});
};
})(window);
Inoltre una volta che lo swap è stato fatto poi spingere il nuovo URL alla cronologia del browser e scorrere verso l'alto della pagina. Uso questo approccio in alcuni luoghi (come la ricerca) per dare una bella esperienza liscia burrosa.
Il tasto posteriore in questo tipo di app può essere problematico; TANTI 'propri' SPAs o disattivare il tasto posteriore o mettere in su con questo comportamento errato. Comunque volevo assicurarmi che il tasto posteriore funzionasse come previsto.
Nota: Per far funzionare il tasto posteriore come previsto abbiamo anche bisogno di ascoltare per il popState
evento. Questo evento viene lanciato quando l'utente naviga indietro o in avanti nella cronologia del browser. Quando questo evento viene licenziato possiamo ricaricare il contenuto dell'URL corrente.
window.addEventListener("popstate", (event) => {
// When the user navigates back, reload the content for the current URL
event.preventDefault();
let url = window.location.href;
// Perform the HTMX AJAX request to load the content for the current state
htmx.ajax('get', url, {
target: '#contentcontainer',
swap: 'innerHTML'
}).then(function () {
// Scroll to the top of the page
window.scrollTo({
top: 0,
behavior: 'smooth'
});
});
});
In questo codice si impedisce il comportamento predefinito del browser popstate con il event.preventDefault()
Chiama. Poi estraiamo l'URL corrente dall' window.location.href
proprietà ed eseguire una richiesta HTMX AJAX per caricare il contenuto per lo stato attuale. Una volta che il contenuto è stato caricato scorriamo in cima alla pagina.
Come accennato in precedenza non è possibile utilizzare anche hx-pushurl
in quanto questo farà sì che il browser per ricaricare la pagina sul backbutton due volte.
Come avrete indovinato, sono un po' un fan di HTMX, combinato con ASP.NET Core e una mattering di Alpine.js che permette ai devs di creare un'esperienza utente davvero piacevole con il minimo sforzo. La cosa principale che preferisco rispetto a quelli più 'completamente formati' frameworks lato client come React / Angolar ecc... è che mi dà ancora un completo server-side rendering pipeline con ASP.NET Core, ma la 'feel' di una SPA. Alpine.js consente una semplice interattività lato client, una caratteristica molto semplice che ho aggiunto recentemente è stato rendere le mie categorie 'nascosto', ma espandere su un click.
Usare Alpine.js per questo significa che non è richiesto nessun JavaScript aggiuntivo.
<div class="mb-8 mt-6 border-neutral-400 dark:border-neutral-600 border rounded-lg" x-data="{ showCategories: false }">
<h4
class="px-5 py-1 bg-neutral-500 bg-opacity-10 rounded-lg font-body text-primary dark:text-white w-full flex justify-between items-center cursor-pointer"
x-on:click="showCategories = !showCategories"
>
Categories
<span>
<i
class="bx text-2xl"
:class="showCategories ? 'bx-chevron-up' : 'bx-chevron-down'"
></i>
</span>
</h4>
<div
class="flex flex-wrap gap-2 pt-2 pl-5 pr-5 pb-2"
x-show="showCategories"
x-cloak
x-transition:enter="max-h-0 opacity-0"
x-transition:enter-end="max-h-screen opacity-100"
x-transition:leave="max-h-screen opacity-100"
x-transition:leave-end="max-h-0 opacity-0"
>
@foreach (var category in ViewBag.Categories)
{
<partial name="_Category" model="category"/>
}
</div>
</div>
Qui potete vedere che uso il x-data
attributo per creare un nuovo oggetto dati Alpine.js, in questo caso showCategories
. Questo è un booleano che è agitato quando il h4
elemento è cliccato. La x-on:click
l'attributo è usato per legare l'evento click alla funzione toggle.
All'interno dell'elenco delle categorie I poi utilizzare il x-show
attributo per mostrare o nascondere l'elenco delle categorie in base al valore di showCategories
. Io uso anche il x-transition
attributo per aggiungere un effetto slide down piacevole quando le categorie sono mostrate o nascoste.
La x-cloak
attributo è usato per evitare che il 'flicker' delle categorie mostrate prima che il JavaScript sia in esecuzione.
Ho una piccola classe CSS definita per questo:
[x-cloak] { display: none !important; }
Così è, un breve articolo su come utilizzare HTMX e un punto di Alpine.js per rendere il vostro sito più reattivo e 'SPA-like'. Spero che abbiate trovato questo utile, se avete domande o commenti non esitate a lasciarli qui sotto.