Eine Paging-View-Komponente ASP.NET Core Tag Helper (Teil 1 die Bare-Bones) (Deutsch (German))

Eine Paging-View-Komponente ASP.NET Core Tag Helper (Teil 1 die Bare-Bones)

Comments

NOTE: Apart from English (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.

Tuesday, 11 March 2025

//

Less than a minute

Einleitung

Ein Arbeitsprojekt neulich erforderte die Umsetzung der Paging-Formular-Ergebnisse. Mein Go-to-Paging-Tag-Helfer war schon immer der Pagination Tag Helper von Darrel O'Neill wie ich schrieb über Hierher aber aus welchem Grund auch immer es ist nur Einstellung der Arbeit Für mich. Anstatt also zu versuchen, durch das zu puzzeln, was wie ein verlassenes Projekt an diesem Punkt aussieht, entschied ich mich, eins selbst zu bauen.

Wie immer können Sie die Quelle dafür erhalten auf meinem GitHub

Ich habe eine Beispiel-Site für dieses Projekt hier gehostet

Dies hat Beispiele der Ausgabe wie folgt:

Demo mit Tag Helperg suchen

Anforderungen

Für diesen Tag Helfer hatte ich einige Anforderungen:

  1. Sollte nahtlos mit arbeiten Rückenwind und DaisyUI; meine bevorzugten CSS-Frameworks.
  2. Sollte mit HTMX arbeiten, ohne Probleme zu verursachen.
  3. Sollte eine Seitengröße Dropdown, die HTMX verwendet, um zu drehen (so, wenn Sie nicht verwenden HTMX sollte es noch funktionieren, aber Sie müssen eine Schaltfläche hinzufügen).
  4. Sollte einfach zu konfigurieren und zu verwenden sein
    1. Akzeptiert ein Paging-Modell, so dass es einfach ist, in einer Razor-Seite zu verwenden
    2. Sollte mit ein paar einfachen Parametern konfiguriert werden können
  5. Sollte ein Nuget-Paket sein, damit alle, die Sie große Leute damit spielen können.
  6. Sollte beides ein ViewComponent und ein TagHelper sein, so dass er sowohl in Razor-Seiten als auch in Ansichten verwendet werden kann; in diesem Sinne sollte es auch einen übergeordneten Dafault.cshtml ................................................................................................................................
  7. Funktioniert mit einer einfachen Suchfunktion.

In Zukunft füge ich die Fähigkeit hinzu:

  1. Fügen Sie benutzerdefinierte CSS zu vermeiden, gebunden zu DaisyUI und Tailwind~~ Ich habe diese Fähigkeit bereits hinzugefügt sehen Sie die Demo hier: Veröffentlichungen der Europäischen Gemeinschaften: Januar 2002.
  2. Die Möglichkeit, Seitengrößen zu spezifizieren
  3. Die Möglichkeit, einen benutzerdefinierten JS-Aufruf zum Dropdown der Seitengröße hinzuzufügen (um Ihnen zu erlauben, HTMX NICHT zu verwenden).
  4. Verwenden Sie Alpine, um den Pager aktiver und responsiver zu machen (wie ich es in meinem vorheriger Artikel).

Installation

Der Taghelper ist jetzt ein glänzendes neues Nuget-Paket, so dass Sie es mit dem folgenden Befehl installieren können:

dotnet add package mostlylucid.pagingtaghelper

Sie würden dann die Tag-Helfer zu Ihrem hinzufügen _ViewImports.cshtml Datei wie so:

@addTagHelper *, mostlylucid.pagingtaghelper

Dann können Sie einfach anfangen, es zu benutzen; Ich stelle einige Helfer Klassen zur Verfügung, die Sie verwenden können, um es zu konfigurieren, wie

IPagingModel

Das ist das "Grundzeug", das Sie brauchen, um loszulegen. Es ist eine einfache Schnittstelle, die Sie auf Ihrem Modell implementieren können, um den Abruf zu erhalten. Beachten Sie, dass ViewType ist hier optional es defaults zu TailwindANdDaisy aber Sie können es auf einstellen Custom, Plain oder Bootstrap wenn Sie eine andere Ansicht verwenden möchten.

public enum ViewType
{
TailwindANdDaisy,
Custom,
Plain,
Bootstrap
}

ODER Sie können sogar eine benutzerdefinierte Ansicht festlegen, indem Sie die TagHelper use-local-view Eigentum.

namespace mostlylucid.pagingtaghelper.Models;

public interface IPagingModel
{
    public int Page { get; set; }
    public int TotalItems { get; set; }
    public int PageSize { get; set; }

    public ViewType ViewType { get; set; }
    
    public string LinkUrl { get; set; }
}
namespace mostlylucid.pagingtaghelper.Models;

public interface IPagingSearchModel : IPagingModel
{
    public string? SearchTerm { get; set; }
}

Ich habe diese auch im Projekt umgesetzt, um eine Basis zu liefern:

public abstract class BasePagerModel : IPagingModel
{
    public int Page { get; set; } = 1;
    public int TotalItems { get; set; } = 0;
    public int PageSize { get; set; } = 10;
    public ViewType ViewType { get; set; } = ViewType.TailwindANdDaisy;

    public string LinkUrl { get; set; } = "";

}
public abstract class BasePagerSearchMdodel : BasePagerModel, IPagingSearchModel
{
    public string? SearchTerm { get; set; }
}

Ich werde die Suchfunktion in einem zukünftigen Artikel..

Der TagHelper

Ich habe dann herausgearbeitet, wie ich den TagHelper im Gebrauch aussehen lassen möchte:

<paging
    x-ref="pager"
    hx-boost="true"
    hx-indicator="#loading-modal"
    hx-target="#user-list "
    hx-swap="show:none"
    model="Model"
    pages-to-display="10"
    hx-headers='{"pagerequest": "true"}'>
</paging>

Hier sehen Sie, dass ich einige HTMX-Parameter und das zu verwendende Modell für das Paging gesetzt habe. Ich habe auch die Anzahl der angezeigten Seiten und die Header für die Anfrage eingestellt (damit kann ich die Seite mit HTMX bevölkern).

Die Komponente hat auch eine BUNCH von anderen Config-Elementen, die ich in zukünftigen Artikeln durcharbeiten werde. Wie Sie sehen können, gibt es eine große Anzahl von möglichen Konfigurationen.

<paging css-class=""
        first-last-navigation=""
        first-page-text=""
        next-page-aria-label=""
        next-page-text=""
        page=""
        pages-to-display=""
        page-size=""
        previous-page-text=""
        search-term=""
        skip-forward-back-navigation=""
        skip-back-text=""
        skip-forward-text="true"
        total-items=""
        link-url=""
        last-page-text=""
        show-pagesize=""
        use-htmx=""
        use-local-view=""
        view-type="Bootstrap"
        htmx-target=""
        id=""
></paging>

Der TagHelper ist ziemlich einfach, hat aber eine Reihe von Eigenschaften, die es dem Benutzer ermöglichen, das Verhalten anzupassen (Sie können dies unten in der Ansicht ) abgesehen von den Eigenschaften (die ich hier nicht für Kürze einfügen werde) ist der Code ziemlich einfach:

    /// <summary>
    /// Processes the tag helper to generate the pagination component.
    /// </summary>

    /// <param name="context">The tag helper context.</param>
    /// <param name="output">The tag helper output.</param>
    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
   
        output.TagName = "div";
        
        //Remove all the properties that are not needed for the rendered content.
        output.Attributes.RemoveAll("page");
        output.Attributes.RemoveAll("link-url");
        output.Attributes.RemoveAll("page-size");
        output.Attributes.RemoveAll("total-items");
        output.Attributes.RemoveAll("pages-to-display");
        output.Attributes.RemoveAll("css-class");
        output.Attributes.RemoveAll("first-page-text");
        output.Attributes.RemoveAll("previous-page-text");
        output.Attributes.RemoveAll("skip-back-text");
        output.Attributes.RemoveAll("skip-forward-text");
        output.Attributes.RemoveAll("next-page-text");
        output.Attributes.RemoveAll("next-page-aria-label");
        output.Attributes.RemoveAll("last-page-text");
        output.Attributes.RemoveAll("first-last-navigation");
        output.Attributes.RemoveAll("skip-forward-back-navigation");
        output.Attributes.RemoveAll("model");
        output.Attributes.RemoveAll("show-pagesize");
        output.Attributes.RemoveAll("pagingmodel");
        output.Attributes.RemoveAll("use-local-view");
        
        var pagerId =  PagerId ?? $"pager-{Guid.NewGuid():N}";
        var linkUrl = LinkUrl ?? ViewContext.HttpContext.Request.Path;
        PageSize = Model?.PageSize ?? PageSize ?? 10;
        Page = Model?.Page ?? Page ?? 1;
        ViewType = Model?.ViewType ?? ViewType;
        TotalItems = Model?.TotalItems ?? TotalItems ?? 0;
        if(Model is IPagingSearchModel searchModel)
            SearchTerm = searchModel?.SearchTerm ?? SearchTerm ?? "";
        output.Attributes.SetAttribute("id", pagerId);
        var viewComponentHelper = (IViewComponentHelper)ViewContext.HttpContext.RequestServices.GetService(typeof(IViewComponentHelper))!;
        ((IViewContextAware)viewComponentHelper).Contextualize(ViewContext);

        var pagerModel = PagerModel ?? new PagerViewModel()
        {
            
            ViewType = ViewType,
            UseLocalView = UseLocalView,
            UseHtmx = UseHtmx,
            PagerId = pagerId,
            SearchTerm = SearchTerm,
            ShowPageSize = ShowPageSize,
            Model = Model,
            LinkUrl = linkUrl,
            Page = Page,
            PageSize = PageSize,
            TotalItems = TotalItems,
            PagesToDisplay = PagesToDisplay,
            CssClass = CssClass,
            FirstPageText = FirstPageText,
            PreviousPageText = PreviousPageText,
            SkipBackText = SkipBackText,
            SkipForwardText = SkipForwardText,
            NextPageText = NextPageText,
            NextPageAriaLabel = NextPageAriaLabel,
            LastPageText = LastPageText,
            FirstLastNavigation = FirstLastNavigation,
            SkipForwardBackNavigation = SkipForwardBackNavigation,
            HtmxTarget = HtmxTarget,
            
        };

        var result = await viewComponentHelper.InvokeAsync("Pager", pagerModel);
        output.Content.SetHtmlContent(result);
    }

Sie umfasst folgende Schritte:

  1. Stellen Sie den Namen des Ausgabe-Tags auf div; das ist der Container für den Pager.
  2. Entfernen Sie alle Eigenschaften, die nicht für den gerenderten Inhalt benötigt werden (aber lassen Sie alle bereitgestellten Benutzer, dies ermöglicht eine einfache Anpassung).
  3. Setzen Sie die pagerId auf eine zufällige GUID, wenn nicht angegeben (dies wird wirklich für benutzerdefinierten Code verwendet, Sie können die ID angeben oder lassen Sie einfach diesen Code kümmern).
  4. Setzen Sie die linkUrl auf den aktuellen Pfad, wenn nicht angegeben - dies ermöglicht es Ihnen, dies zu überschreiben, wenn Sie eine andere URL verwenden möchten.
  5. Setzen Sie PageSize, Page, ViewType, TotalItems und SearchTerm auf das Modell, falls vorhanden oder die Standardeinstellung, falls nicht. Dies ermöglicht es uns, einfach in der IPagingModel und den Pager ohne weitere Konfiguration arbeiten lassen.
  6. Setzen Sie das ID-Attribut auf die pagerId.
  7. Holen Sie sich den ViewComponentHelper aus dem DI-Container und kontextualisieren Sie ihn mit dem aktuellen ViewContext.
  8. Erstellen Sie eine neue PagerViewModel mit den Eigenschaften, die auf die Werte gesetzt sind, die wir haben oder die Standardwerte, wenn nicht angegeben.
  9. Einberufen der Pager ViewComponent mit dem PagerViewModel und setzen Sie den Ausgabeinhalt auf das Ergebnis.

Wieder ganz ganz einfach.

Der ViewComponent

Die Ansicht

Die Ansicht für den ViewComponent ist ziemlich einfach; es ist nur eine Schleife durch die Seiten und ein paar Links zu den ersten, letzten, nächsten und vorherigen Seiten.

Complete source code for the Default TailwindUI & Daisy view
@model mostlylucid.pagingtaghelper.Components.PagerViewModel
@{
    var totalPages = (int)Math.Ceiling((double)Model.TotalItems! / (double)Model.PageSize!);
    var pageSizes = new List<int>();
    if (Model.ShowPageSize)
    {
        // Build a dynamic list of page sizes.

        // Fixed steps as a starting point.
        int[] fixedSteps = { 10, 25, 50, 75, 100, 125, 150, 200, 250, 500, 1000 };

        // Add only those fixed steps that are less than or equal to TotalItems.
        foreach (var step in fixedSteps)
        {
            if (step <= Model.TotalItems)
            {
                pageSizes.Add(step);
            }
        }

        // If TotalItems is greater than the largest fixed step,
        // add additional steps by doubling until reaching TotalItems.
        if (Model.TotalItems > fixedSteps.Last())
        {
            int next = fixedSteps.Last();
            while (next < Model.TotalItems)
            {
                next *= 2;
                // Only add if it doesn't exceed TotalItems.
                if (next < Model.TotalItems)
                {
                    pageSizes.Add(next);
                }
            }

            // Always include the actual TotalItems as the maximum option.
            if (!pageSizes.Contains(Model.TotalItems.Value))
            {
                pageSizes.Add(Model.TotalItems.Value);
            }
        }
    }
}
@if (totalPages > 1)
{
    <div class="@Model.CssClass flex items-center justify-center" id="pager-container">
        @if (Model.ShowPageSize)
        {
            var pagerId = Model.PagerId;
            var htmxAttributes = Model.UseHtmx
                ? $"hx-get=\"{Model.LinkUrl}\" hx-trigger=\"change\" hx-include=\"#{pagerId} [name='page'], #{pagerId} [name='search']\" hx-push-url=\"true\""
                : "";


            <!-- Preserve current page -->
            <input type="hidden" name="page" value="@Model.Page"/>
            <input type="hidden" name="search" value="@Model.SearchTerm"/>
            <input type="hidden" class="useHtmx" value="@Model.UseHtmx.ToString().ToLowerInvariant()"/>
            if (!Model.UseHtmx)
            {
                <input type="hidden" class="linkUrl" value="@Model.LinkUrl"/>
            }

            <!-- Page size select with label -->
            <div class="flex items-center mr-8">
                <label for="pageSize-@pagerId" class="text-sm text-gray-600 mr-2">Page size:</label>
                <select id="pageSize-@pagerId"
                        name="pageSize"
                        class="border rounded select select-primary select-sm pt-0 mt-0 min-w-[80px] pr-4"
                        @Html.Raw(htmxAttributes)>
                    @foreach (var option in pageSizes.ToList())
                    {
                        var optionString = option.ToString();
                        if (option == Model.PageSize)
                        {
                            <option value="@optionString" selected="selected">@optionString</option>
                        }
                        else
                        {
                            <option value="@optionString">@optionString</option>
                        }
                    }
                </select>
            </div>
        }

        @* "First" page link *@
        @if (Model.FirstLastNavigation && Model.Page > 1)
        {
            var href = $"{Model.LinkUrl}?page=1&pageSize={Model.PageSize}";
            if (!string.IsNullOrEmpty(Model.SearchTerm))
            {
                href += $"&search={Model.SearchTerm}";
            }

            <a class="btn btn-sm"
               href="@href">
                @Model.FirstPageText
            </a>
        }

        @* "Previous" page link *@
        @if (Model.Page > 1)
        {
            var href = $"{Model.LinkUrl}?page={Model.Page - 1}&pageSize={Model.PageSize}";
            if (!string.IsNullOrEmpty(Model.SearchTerm))
            {
                href += $"&search={Model.SearchTerm}";
            }

            <a class="btn btn-sm"
               href="@href">
                @Model.PreviousPageText
            </a>
        }

        @* Optional skip back indicator *@
        @if (Model.SkipForwardBackNavigation && Model.Page > Model.PagesToDisplay)
        {
            <a class="btn btn-sm btn-disabled">
                @Model.SkipBackText
            </a>
        }

        @* Determine visible page range *@
        @{
            int halfDisplay = Model.PagesToDisplay / 2;
            int startPage = Math.Max(1, Model.Page.Value - halfDisplay);
            int endPage = Math.Min(totalPages, startPage + Model.PagesToDisplay - 1);
            startPage = Math.Max(1, endPage - Model.PagesToDisplay + 1);
        }
        @for (int i = startPage; i <= endPage; i++)
        {
            var href = $"{Model.LinkUrl}?page={i}&pageSize={Model.PageSize}";
            if (!string.IsNullOrEmpty(Model.SearchTerm))
            {
                href += $"&search={Model.SearchTerm}";
            }

            <a data-page="@i" class="btn btn-sm mr-2 @(i == Model.Page ? "btn-active" : "")"
               href="@href">
                @i
            </a>
        }

        @* Optional skip forward indicator *@
        @if (Model.SkipForwardBackNavigation && Model.Page < totalPages - Model.PagesToDisplay + 1)
        {
            <a class="btn btn-sm btn-disabled mr-2">
                @Model.SkipForwardText
            </a>
        }

        @* "Next" page link *@
        @if (Model.Page < totalPages)
        {
            var href = $"{Model.LinkUrl}?page={Model.Page + 1}&pageSize={Model.PageSize}";
            if (!string.IsNullOrEmpty(Model.SearchTerm))
            {
                href += $"&search={Model.SearchTerm}";
            }

            <a class="btn btn-sm mr-2"
               href="@href"
               aria-label="@Model.NextPageAriaLabel">
                @Model.NextPageText
            </a>
        }

        @* "Last" page link *@
        @if (Model.FirstLastNavigation && Model.Page < totalPages)
        {
            var href = $"{Model.LinkUrl}?page={totalPages}&pageSize={Model.PageSize}";
            if (!string.IsNullOrEmpty(Model.SearchTerm))
            {
                href += $"&search={Model.SearchTerm}";
            }

            <a class="btn btn-sm"
               href="@href">
                @Model.LastPageText
            </a>
        }

        <!-- Page info text with left margin for separation -->
        <div class="text-sm text-neutral-500 ml-8">
            Page @Model.Page of @totalPages (Total items: @Model.TotalItems)
        </div>
    </div>
}
Dies ist in ein paar Abschnitte unterteilt:
  1. Die Seitengröße Dropdown
  2. Die ersten, letzten, nächsten und vorherigen Links
  3. Die skip back und skip forward Links
  4. Die Seite verlinkt
  5. Die Seite Info Text

Die Seitengröße Dropdown

Eine Sache, die ich von der ursprünglichen Tag-Helfer fehlte, war eine Seitengröße Dropdown. Dies ist eine einfache Auswahlliste, können Sie sehen, dass ich zuerst beginnen, indem Sie fixedSteps Das sind nur ein paar feste Schritte, die ich für den Dropdown verwenden möchte. Dann schleife ich diese durch und füge sie zur Liste hinzu. Eine Gewohnheit, die ich immer habe, ist, eine 'alle' Option zu haben, also füge ich die gesamten Elemente zur Liste hinzu, wenn es nicht schon da ist.

@{
    var totalPages = (int)Math.Ceiling((double)Model.TotalItems! / (double)Model.PageSize!);
    var pageSizes = new List<int>();
    if (Model.ShowPageSize)
    {
        // Build a dynamic list of page sizes.

        // Fixed steps as a starting point.
        int[] fixedSteps = { 10, 25, 50, 75, 100, 125, 150, 200, 250, 500, 1000 };

        // Add only those fixed steps that are less than or equal to TotalItems.
        foreach (var step in fixedSteps)
        {
            if (step <= Model.TotalItems)
            {
                pageSizes.Add(step);
            }
        }

        // If TotalItems is greater than the largest fixed step,
        // add additional steps by doubling until reaching TotalItems.
        if (Model.TotalItems > fixedSteps.Last())
        {
            int next = fixedSteps.Last();
            while (next < Model.TotalItems)
            {
                next *= 2;
                // Only add if it doesn't exceed TotalItems.
                if (next < Model.TotalItems)
                {
                    pageSizes.Add(next);
                }
            }

            // Always include the actual TotalItems as the maximum option.
            if (!pageSizes.Contains(Model.TotalItems.Value))
            {
                pageSizes.Add(Model.TotalItems.Value);
            }
        }
    }
}

Ich gebe dies dann auf die Seite

  @if (Model.ShowPageSize)
        {
            var pagerId = Model.PagerId;
            var htmxAttributes = Model.UseHtmx
                ? $"hx-get=\"{Model.LinkUrl}\" hx-trigger=\"change\" hx-include=\"#{pagerId} [name='page'], #{pagerId} [name='search']\" hx-push-url=\"true\""
                : "";


            <!-- Preserve current page -->
            <input type="hidden" name="page" value="@Model.Page"/>
            <input type="hidden" name="search" value="@Model.SearchTerm"/>
            <input type="hidden" class="useHtmx" value="@Model.UseHtmx.ToString().ToLowerInvariant()"/>
            if (!Model.UseHtmx)
            {
                <input type="hidden" class="linkUrl" value="@Model.LinkUrl"/>
            }

            <!-- Page size select with label -->
            <div class="flex items-center mr-8">
                <label for="pageSize-@pagerId" class="text-sm text-gray-600 mr-2">Page size:</label>
                <select id="pageSize-@pagerId"
                        name="pageSize"
                        class="border rounded select select-primary select-sm pt-0 mt-0 min-w-[80px] pr-4"
                        @Html.Raw(htmxAttributes)>
                    @foreach (var option in pageSizes.ToList())
                    {
                        var optionString = option.ToString();
                        if (option == Model.PageSize)
                        {
                            <option value="@optionString" selected="selected">@optionString</option>
                        }
                        else
                        {
                            <option value="@optionString">@optionString</option>
                        }
                    }
                </select>
            </div>
        }

Sie sehen, dass ich optional einige HTMX-Attribute verwende, um die Seitengröße an den Server weiterzugeben und die Seite zu aktualisieren, während die aktuelle Seite und der Suchparameter (falls vorhanden) beibehalten werden.

Zusätzlich, wenn Sie spezif use-htmx=false als Parameter auf dem Tag-Helfer wird es diese nicht ausgeben, sondern wird Ihnen erlauben, einige JS I als HTML-Helfer zur Aktualisierung der Seitengröße zu verwenden.

@Html.PageSizeOnchangeSnippet()
    

Dies ist ein einfaches Skript, das die Seitengröße aktualisiert und die Seite neu lädt (beachten Sie, dass dies für Plain CSS / Bootstrap noch nicht funktioniert, da ich die Eigenschaftsnamen usw. ausarbeiten muss).

document.addEventListener("DOMContentLoaded", function () {
    document.body.addEventListener("change", function (event) {
        const selectElement = event.target.closest("#pager-container select[name='pageSize']");
        if (!selectElement) return;

        const pagerContainer = selectElement.closest("#pager-container");
        const useHtmxInput = pagerContainer.querySelector("input.useHtmx");
        const useHtmx = useHtmxInput ? useHtmxInput.value === "true" : true; // default to true

        if (!useHtmx) {
            const pageInput = pagerContainer.querySelector("[name='page']");
            const searchInput = pagerContainer.querySelector("[name='search']");

            const page = pageInput ? pageInput.value : "1";
            const search = searchInput ? searchInput.value : "";
            const pageSize = selectElement.value;
            const linkUrl =  pagerContainer.querySelector("input.linkUrl").value ?? "";
            
            const url = new URL(linkUrl, window.location.origin);
            url.searchParams.set("page", page);
            url.searchParams.set("pageSize", pageSize);

            if (search) {
                url.searchParams.set("search", search);
            }

            window.location.href = url.toString();
        }
    });
});

HTMX-Integration

Die HTMX-Integration ist ziemlich einfach, da HTMX auf Child-Elemente kaskadiert, die wir die HTMX-Parameter auf dem übergeordneten Element definieren können und sie geerbt werden.

  • hx-boost="true" - das benutzt die nifty hx-Boost-Funktion um das Klick-Ereignis abzufangen und die Anfrage per HTMX zu senden.
  • hx-indicator="#loading-modal" - dies hat einen Lademodal, der während der Bearbeitung der Anfrage angezeigt wird.
  • hx-target="#user-list" - das ist das Element, das die Antwort austauscht, in diesem Fall die Benutzerliste. Hinweis: Dies beinhaltet derzeit den Pager für Einfachheit; Sie können dies aktiver mit Alpine machen (wie in meinem früherer Artikel == Weblinks ==== Einzelnachweise ==
  • hx-swap="show:keine"

Das Lademodul

Dies ist ziemlich einfach und verwendet DaisyUI, Boxicons und Tailwind, um eine einfache Lademodalität zu erstellen.

<div id="loading-modal" class="modal htmx-indicator">
    <div class="modal-box flex flex-col items-center justify-center">
        <h2 class="text-lg font-semibold">Loading...</h2>
        <i class="bx bx-loader bx-spin text-3xl mt-2"></i>
    </div>
</div>

hx-indicator="#loading-modal" gibt dann an, dass, wenn eine HTMX-Anfrage ausgeführt wird, diese modal angezeigt wird.

Zukünftige Merkmale

Also, das ist Teil 1, es gibt offensichtlich eine LOT mehr zu decken und ich werde in zukünftigen Artikeln; einschließlich der Beispiel-Website, alternative Ansichten, die Suchfunktionalität und die benutzerdefinierte CSS.

logo

©2024 Scott Galloway