LET OP: Binnenkort, gewoon de laatste hand aan het. Volg GitHub! .
Dit is alleen maar om jullie te laten zien wat IK BEN het boeken van vooruitgang met deze controle! Het zal het wachten waard zijn.
Na maanden van evolutie en waardevolle feedback van de community (5.7k+ downloads!), ben ik blij om aan te kondigen dat de PagingTagHelper bibliotheek versie 1.0.0 heeft bereikt. Dit is niet alleen een versie nummer hobbel ... het vertegenwoordigt een volledige rijping van de bibliotheek met functies die het geschikt maken voor real-world, productie toepassingen.
Als je deze serie hebt gevolgd, zul je je herinneren dat we begonnen zijn met blote botten paging, toegevoegd sorteerbare kopteksten, en gewonnen paginagrootteregeling. Versie 1.0.0 neemt alles wat we hebben geleerd en voegt kritische enterprise features:
Laten we in elk van deze functies duiken en zien hoe ze samenwerken om een echt flexibele paginatie-oplossing te creëren.
Traditionele paginatie werkt prachtig met SQL databases waar u gemakkelijk SKIP en TAKE records. Maar wat gebeurt er als je werkt met NoSQL databases zoals Cosmos DB, DynamoDB, of Azure Table Storage? Deze databases ondersteunen geen offset-based pagination in plaats daarvan, ze gebruiken continuation tokens.
Hier is hoe continuation token pagination verschilt van traditionele paging:
graph TD
A[Traditional Paging] --> B[Page 1: OFFSET 0 LIMIT 10]
A --> C[Page 2: OFFSET 10 LIMIT 10]
A --> D[Page 3: OFFSET 20 LIMIT 10]
E[Token-Based Paging] --> F[Page 1: No token]
F --> G[Returns: Data + Token_A]
G --> H[Page 2: Token_A]
H --> I[Returns: Data + Token_B]
I --> J[Page 3: Token_B]
style A stroke:#0ea5e9,stroke-width:3px
style E stroke:#ec4899,stroke-width:3px
Traditionele pagina's:
Pagina's op basis van token:
Het nieuwe <continuation-pager> tag helper maakt het implementeren van token-gebaseerde paginatie eenvoudig. Eerst, maak een model dat implementeert IContinuationPagingModel:
public class ProductPagingViewModel : IContinuationPagingModel
{
public string? NextPageToken { get; set; }
public bool HasMoreResults { get; set; }
public int PageSize { get; set; } = 25;
public int CurrentPage { get; set; } = 1;
public Dictionary<int, string>? PageTokenHistory { get; set; }
public ViewType ViewType { get; set; } = ViewType.TailwindAndDaisy;
// Your actual data
public List<Product> Products { get; set; } = new();
}
De interface is minimaal maar krachtig. Laten we eens kijken naar wat elke eigenschap doet:
NextPageToken: Het token om de volgende pagina op te halen (geleverd door uw database)HasMoreResults: Booleaans geeft aan of er meer pagina's zijnPageSize: Items per paginaCurrentPage: Alleen weergeven paginanummer voor UIPageTokenHistory: Dictionary mapping pagina nummers to tokens voor achteruit navigatieViewType: Welk CSS-kader te gebruiken voor renderingLaten we nu een controller actie implementeren die Cosmos DB-stijl paginatie simuleert:
[Route("Products")]
public async Task<IActionResult> Products(
int currentPage = 1,
int pageSize = 25,
string? pageToken = null,
string? tokenHistory = null)
{
// Simulate fetching from Cosmos DB
var cosmosResults = await _cosmosService.GetProductsAsync(
pageSize: pageSize,
continuationToken: pageToken
);
// Deserialize token history for backward navigation
var history = string.IsNullOrEmpty(tokenHistory)
? new Dictionary<int, string>()
: JsonSerializer.Deserialize<Dictionary<int, string>>(tokenHistory)
?? new Dictionary<int, string>();
// Store current token in history
if (!string.IsNullOrEmpty(pageToken))
{
history[currentPage] = pageToken;
}
var viewModel = new ProductPagingViewModel
{
CurrentPage = currentPage,
PageSize = pageSize,
NextPageToken = cosmosResults.ContinuationToken,
HasMoreResults = cosmosResults.HasMoreResults,
PageTokenHistory = history,
Products = cosmosResults.Items
};
if (Request.IsHtmx())
{
return PartialView("_ProductList", viewModel);
}
return View(viewModel);
}
Deze implementatie laat zien hoe tokengeschiedenis backward navigation mogelijk maakt. Zonder dit zou continuation token pagination alleen "Next" knoppen ondersteunen. Door een woordenboek van pagina-to-to-token mappings te behouden, kunnen we zowel "Vorige" als "Next" navigatie ondersteunen.
Hier is de stroom van token accumulatie gevisualiseerd:
sequenceDiagram
participant User
participant Controller
participant Database
participant TokenHistory
User->>Controller: Request Page 1 (no token)
Controller->>Database: Query with no token
Database-->>Controller: Data + Token_A
Controller->>TokenHistory: Store Token_A for page 1
Controller-->>User: Display Page 1
User->>Controller: Request Page 2 (Token_A)
Controller->>Database: Query with Token_A
Database-->>Controller: Data + Token_B
Controller->>TokenHistory: Add Token_B for page 2
Controller-->>User: Display Page 2
User->>Controller: Request Page 1 (retrieve from history)
Controller->>TokenHistory: Get Token for Page 1
Controller->>Database: Query with Token_A
Database-->>Controller: Data + Token_A
Controller-->>User: Display Page 1
In uw Razor-weergave is het gebruik van de continuation pager eenvoudig:
@model ProductPagingViewModel
<div id="product-container">
<table class="table">
<thead>
<tr>
<th>Product</th>
<th>Company</th>
<th>Price</th>
</tr>
</thead>
<tbody>
@foreach (var product in Model.Products)
{
<tr>
<td>@product.Name</td>
<td>@product.CompanyName</td>
<td>[email protected]("N2")</td>
</tr>
}
</tbody>
</table>
<continuation-pager
model="Model"
htmx-target="#product-container"
show-page-number="true"
show-pagesize="true" />
</div>
De tag-helper automatisch:
HasMoreResults is onjuistHet geniale van de token geschiedenis benadering is dat het is volledig optioneel. Als je alleen "Next" navigatie (oneindige scroll, bijvoorbeeld), kunt u token geschiedenis volledig negeren:
<continuation-pager
model="Model"
enable-token-accumulation="false"
show-page-number="false" />
Dit maakt gewoon een "Next" knop zonder pagina-indicatoren of geschiedenisbeheer.
Voor volledige navigatie wordt de tokengeschiedenis automatisch geserialiseerd als JSON in de query string. Hier is hoe een URL eruit ziet met tokengeschiedenis:
/Products?currentPage=3&pageSize=25&pageToken=abc123&tokenHistory=%7B%221%22%3A%22xyz789%22%2C%222%22%3A%22abc123%22%7D
De tokenHistory parameter bevat het gecodeerde woordenboek, waardoor achteruit navigatie naadloos.
Een van de belangrijkste UX verbeteringen in de continuation pager is genummerde paginaknoppen. Als u navigeert naar voren, de pager toont klikbare paginanummers voor alle bezochte pagina's:
Initial page 1: [Next →]
After next click: [← Prev] [1] [2 active] [3 disabled] [Next →]
After next click: [← Prev] [1] [2] [3 active] [4 disabled] [Next →]
Click page 2: [← Prev] [1] [2 active] [3] [4 disabled] (no next - not visited yet)
Dit biedt traditionele pagination UX terwijl het onderhouden van token-gebaseerde backend architectuur. De implementatie slaat tokens voor elke bezochte pagina, waardoor directe navigatie naar een eerder bezochte pagina.
Beperkende groei van de geschiedenis:
Om ongebonden geheugengebruik te voorkomen, ingesteld max-history-pages (standaard: 20):
<continuation-pager
model="Model"
max-history-pages="50"
show-page-number="true" />
Wanneer de limiet is bereikt, worden de oudste pagina tokens automatisch gesnoeid.
Dit is het belangrijkste kenmerk van de continuation pager implementatie.
Continuation tokens zijn alleen geldig met dezelfde query context (filters, soorten, zoekopdrachten) die ze gegenereerd hebben. Het gebruik van een token met verschillende query parameters zal onjuiste gegevens teruggeven of volledig falen.
De vervolg pager behoudt automatisch ALLE zoekparameters behalve de eigen:
<!-- URL with filters -->
/Products?category=electronics&brand=acme&minPrice=100
<!-- After clicking Next -->
/Products?category=electronics&brand=acme&minPrice=100¤tPage=2&pageToken=xyz123&tokenHistory={...}
<!-- All filters preserved! Token is valid because query context matches. -->
U kunt dit gedrag uitschakelen indien nodig:
<continuation-pager
model="Model"
preserve-query-parameters="false" />
Maar dit is sterk ontmoedigd Tenzij je absoluut zeker bent dat je tokens niet afhankelijk zijn van query context.
Waarom dit belangrijk is:
Cosmos DB voorbeeld:
// Page 1 with filter
var query = container.GetItemQueryIterator<Product>(
"SELECT * FROM c WHERE c.category = 'electronics'",
continuationToken: null
);
var response = await query.ReadNextAsync();
// Returns: Products + Token_A
// Page 2 with SAME filter - Token_A is valid
var query2 = container.GetItemQueryIterator<Product>(
"SELECT * FROM c WHERE c.category = 'electronics'",
continuationToken: Token_A // ✅ Works!
);
// Page 2 with DIFFERENT filter - Token_A is invalid
var query3 = container.GetItemQueryIterator<Product>(
"SELECT * FROM c WHERE c.category = 'computers'",
continuationToken: Token_A // ❌ Wrong results or error!
);
De automatische parameter bewaring van de vervolgpager zorgt ervoor dat tokens altijd worden gebruikt met hun oorspronkelijke query-context.
Moderne toepassingen dienen wereldwijd publiek, en paginatie controles moeten de taal van uw gebruikers spreken. Versie 1.0.0 omvat uitgebreide lokalisatie ondersteuning ingebouwd in de bibliotheek.
De bibliotheek verscheept met vertalingen voor 8 talen:
en Engels (onvertaald)
| de Duits (Deutsch)
| es Spaans (Español)
| fr Frans (Français)
| it Italiaans (Italiano)
| pt Portugees (Português)
| ja Japans ( . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
| zh-Hans Vereenvoudigd Chinees ( . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Alle tekst is gelokaliseerd, inclusief:
Het lokalisatiesysteem wordt aangedreven door .resx resource-bestanden, waardoor het gemakkelijk is om uw eigen talen toe te voegen. Alle resource-bestanden zijn in mostlylucid.pagingtaghelper/Resources/.
Het gebruik van localisatie is eenvoudig. language attribuut:
<paging
model="Model"
language="de"
show-summary="true"
first-last-navigation="true" />
Hiermee wordt alle tekst in het Duits weergegeven:
<!-- Previous button -->
<button>‹ Vorherige</button>
<!-- Summary -->
<div class="text-sm text-gray-600">
Zeige 1 bis 10 von 256 Einträgen
</div>
<!-- Next button -->
<button>Nächste ›</button>
Voor dynamische taalschakeling op basis van gebruikersvoorkeuren, stelt u de taal in uw controller in:
public async Task<IActionResult> Products(
int page = 1,
int pageSize = 10,
string language = "en")
{
var pagingModel = await GenerateModel(page, pageSize);
ViewBag.SelectedLanguage = language;
return View(pagingModel);
}
Maak dan in uw ogen een taalkiezer aan:
@{
var selectedLanguage = ViewBag.SelectedLanguage as string ?? "en";
var languages = new Dictionary<string, string>
{
{ "en", "English" },
{ "de", "German" },
{ "es", "Spanish" },
{ "fr", "French" },
{ "it", "Italian" },
{ "pt", "Portuguese" },
{ "ja", "Japanese" },
{ "zh-Hans", "Chinese" }
};
}
<select onchange="window.location.href='/Products?language=' + this.value">
@foreach (var lang in languages)
{
<option value="@lang.Key" selected="@(lang.Key == selectedLanguage)">
@lang.Value
</option>
}
</select>
<paging
model="Model"
language="@selectedLanguage"
link-url="/Products" />
U kunt ook individuele tekststrings overschrijven terwijl u nog steeds profiteert van localisatie voor andere elementen:
<paging
model="Model"
language="ja"
previous-page-text="戻る"
next-page-text="次へ"
summary-template="全{TotalItems}件中 {StartItem}~{EndItem}件を表示" />
De PagingLocalizer service verwerkt cultuur-specifieke opmaak automatisch. Als u een ongeldige taalcode doorgeeft, valt het sierlijk terug naar het Engels.
Voor HTMX integratie, wilt u de taal te behouden in alle verzoeken:
<script>
htmx.on('htmx:configRequest', function(event) {
if (event.detail.path.includes('/Products')) {
event.detail.parameters.language = '@selectedLanguage';
}
});
</script>
Dit zorgt ervoor dat HTMX partial view updates de geselecteerde taal behouden.
Een van de belangrijkste verbeteringen in v1.0.0 is de invoering van flexibele JavaScript modi. Eerder had je een booleaanse keuze: use-htmx="true" of use-htmx="false". Nu heb je vijf verschillende modi, elk geoptimaliseerd voor verschillende scenario's.
Hier is de volledige indeling van JavaScript modi:
graph TD
A[JavaScript Modes] --> B[HTMX]
A --> C[HTMXWithAlpine]
A --> D[Alpine]
A --> E[PlainJS]
A --> F[NoJS]
B --> B1[Uses HTMX for partial updates]
B --> B2[hx-get, hx-target, hx-swap]
C --> C1[HTMX + Alpine.js directives]
C --> C2[Enhanced interactivity]
D --> D1[Pure Alpine.js]
D --> D2[x-data, @click handlers]
E --> E1[Vanilla JavaScript]
E --> E2[onclick handlers]
F --> F1[Zero JavaScript]
F --> F2[Standard anchor links & forms]
Laten we elke modus in actie zien:
1. HTMX-modus (standaard)
<paging
model="Model"
js-mode="HTMX"
htmx-target="#results-container" />
Renders:
<button hx-get="/Products?page=2" hx-target="#results-container" hx-swap="outerHTML">
Next ›
</button>
Perfect voor dynamische pagina-updates zonder volledige pagina-herladen. Dit is de aanbevolen modus voor moderne ASP.NET Core toepassingen.
2. HTMXMetAlpine-modus
<paging
model="Model"
js-mode="HTMXWithAlpine"
htmx-target="#results-container" />
Renders:
<button
x-data
hx-get="/Products?page=2"
hx-target="#results-container"
hx-swap="outerHTML">
Next ›
</button>
Combineert HTMX voor navigatie met Alpine.js voor extra client-side interactiviteit. Gebruik dit wanneer je reactieve UI-elementen nodig hebt naast paginatie (loading-indicatoren, animaties, client-side validatie).
3. Alpenmodus
<paging
model="Model"
js-mode="Alpine" />
Renders:
<button
x-data
@click="window.location.href = '/Products?page=2'">
Next ›
</button>
Pure Alpine.js zonder HTMX. Handig als je al Alpine.js gebruikt maar geen HTMX afhankelijkheden wilt.
4. PlainJS-modus
<paging
model="Model"
js-mode="PlainJS" />
Renders:
<button onclick="window.location.href = '/Products?page=2'">
Next ›
</button>
Geen kaderafhankelijkheden, alleen vanille JavaScript. Deze modus bevat ook een helper voor paginagroottewijzigingen:
@Html.PageSizeOnchangeSnippet()
Dit injecteert de nodige JavaScript voor het verwerken van paginagrootte dropdown veranderingen zonder HTMX.
5. NoJS-modus
<paging
model="Model"
js-mode="NoJS" />
Renders:
<!-- Navigation uses standard anchor links -->
<a href="/Products?page=2">Next ›</a>
<!-- Page size uses a form with submit button -->
<form method="get" action="/Products">
<input type="hidden" name="page" value="1" />
<select name="pageSize" onchange="this.form.submit()">
<option value="10">10</option>
<option value="25" selected>25</option>
<option value="50">50</option>
</select>
<noscript>
<button type="submit">Update</button>
</noscript>
</form>
Zero JavaScript vereist. Perfect voor:
De schoonheid van dit systeem is dat alle modi uw bestaande query parameters behouden. Of u nu filtert op categorie, zoeken of sorteren, de paginatie behoudt automatisch uw status.
Voor achterwaartse compatibiliteit, de oude use-htmx attribuut werkt nog steeds:
<!-- Old syntax (still works) -->
<paging model="Model" use-htmx="true" />
<!-- Equivalent to js-mode="HTMX" -->
<paging model="Model" use-htmx="false" />
<!-- Equivalent to js-mode="PlainJS" -->
Ik adviseer echter om te migreren naar de nieuwe js-mode attribuut voor duidelijkheid:
<!-- New syntax (recommended) -->
<paging model="Model" js-mode="HTMX" />
<paging model="Model" js-mode="PlainJS" />
Versie 1.0.0 introduceert twee belangrijke ViewType toevoegingen die betrekking hebben op gemeenschappelijke real-world scenario's.
Eerder, als je wilde TailwindCSS styling, je kreeg de TailwindAndDaisy weergave die DaisyUI componenten gebruikt. Dit is geweldig als je DaisyUI al gebruikt, maar wat als je pure Tailwind wilt zonder de DaisyUI afhankelijkheid?
Enter ViewType.Tailwind:
<paging
model="Model"
view-type="Tailwind" />
Dit maakt alleen gebruik van standaard Tailwind utility classes:
<div class="flex gap-2 items-center">
<button class="px-4 py-2 text-sm font-medium rounded-md bg-blue-600 text-white hover:bg-blue-700">
‹ Previous
</button>
<div class="px-3 py-1 text-sm font-medium bg-gray-100 dark:bg-gray-700 dark:text-white rounded-md">
Page 1
</div>
<button class="px-4 py-2 text-sm font-medium rounded-md bg-blue-600 text-white hover:bg-blue-700">
Next ›
</button>
</div>
Nee btn, badge, of join Klassen, gewoon pure Tailwind. Dit geeft u volledige controle over styling zonder onderdelenbibliotheek afhankelijkheden.
Vergelijking:
WeergaveType CSS Framework Onderdelenbibliotheek Gebruik Case
|----------|---------------|-------------------|----------|
| TailwindAndDaisy TailwindCSS DaisyUI Projecten die al DaisyUI gebruiken
| Tailwind Puur Tailwind CSS Geen Puur Tailwind projecten
| Bootstrap Bootstrap Bootstrap componenten Bootstrap projecten
| Plain Ingebedde CSS Geen Geen Framework afhankelijkheden
| NoJS Ingebedde CSS GeenZero JavaScript vereisten
De NoJS ViewType combineert nul JavaScript met de Plain CSS styling:
<paging
model="Model"
view-type="NoJS"
show-pagesize="true" />
Belangrijkste verschillen met andere weergavetypen:
<a href="/Products?page=2" class="pager-button">Next ›</a>
<form method="get" action="/Products" class="page-size-form">
<!-- Preserves all current query parameters as hidden inputs -->
<input type="hidden" name="search" value="laptop" />
<input type="hidden" name="category" value="electronics" />
<!-- Reset to page 1 when changing page size -->
<input type="hidden" name="page" value="1" />
<label for="pageSize">Items per page:</label>
<select name="pageSize" onchange="this.form.submit()">
<option value="10">10</option>
<option value="25" selected>25</option>
<option value="50">50</option>
</select>
<!-- Button visible when JavaScript is disabled -->
<noscript>
<button type="submit" class="page-size-button">Update</button>
</noscript>
</form>
De onchange="this.form.submit()" biedt gemak wanneer JavaScript beschikbaar is, maar de <noscript> knop zorgt voor volledige functionaliteit als het niet zo is.
Een van de meest frustrerende aspecten van paginatie implementaties is het verliezen van uw filters, zoektermen, of sorteren orde bij het navigeren tussen pagina's. Versie 1.0.0 lost dit elegant door automatisch alle queryparameters behouden, behalve de eigen parameters van de paginatiecontrole.
Deze functie werkt identiek over zowel reguliere piepers als vervolgpiepers, en over alle JavaScript-modi en ViewTypes.
Zo werkt het intern:
string BuildQueryString(string? token, int page)
{
var query = new Dictionary<string, string>();
// Define continuation pager's own parameters that should be excluded from preservation
var pagerParams = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"pageSize", "currentPage", "pageToken", "tokenHistory"
};
// Add parameter prefix variants if using prefixed parameters
if (!string.IsNullOrEmpty(Model.ParameterPrefix))
{
pagerParams.Add($"{Model.ParameterPrefix}_pageSize");
pagerParams.Add($"{Model.ParameterPrefix}_currentPage");
pagerParams.Add($"{Model.ParameterPrefix}_pageToken");
pagerParams.Add($"{Model.ParameterPrefix}_tokenHistory");
}
// Preserve all existing query parameters (except pager's own) if enabled
if (Model.PreserveQueryParameters)
{
foreach (var param in ViewContext.HttpContext.Request.Query)
{
if (!pagerParams.Contains(param.Key))
{
query[param.Key] = param.Value.ToString();
}
}
}
// Add continuation pager parameters (with prefix if specified)
var pageSizeParam = Model.GetParameterName("pageSize");
var currentPageParam = Model.GetParameterName("currentPage");
var pageTokenParam = Model.GetParameterName("pageToken");
var tokenHistoryParam = Model.GetParameterName("tokenHistory");
query[pageSizeParam] = pageSize.ToString();
query[currentPageParam] = page.ToString();
if (!string.IsNullOrEmpty(token))
query[pageTokenParam] = token;
if (Model.EnableTokenAccumulation)
query[tokenHistoryParam] = tokenHistoryJson;
return string.Join("&", query.Select(kvp =>
$"{Uri.EscapeDataString(kvp.Key)}={Uri.EscapeDataString(kvp.Value)}"));
}
Deze aanpak houdt het volgende in:
Scenario 1: Zoeken + Paginatie
Initial URL: /Products?search=laptop&category=electronics&page=1
Click Next: /Products?search=laptop&category=electronics&page=2
Change Page Size: /Products?search=laptop&category=electronics&page=1&pageSize=50
Scenario 2: Sorteren + Paginatie
Initial URL: /Products?orderBy=price&descending=true&page=1
Click Page 3: /Products?orderBy=price&descending=true&page=3
Scenario 3: Continuation Pager met filters
Initial URL: /Products?category=electronics&brand=acme
Click Next: /Products?category=electronics&brand=acme¤tPage=2&pageToken=abc123&tokenHistory={...}
Dezelfde bewaring werkt in vormen (NoJS-modus). Bij het renderen van het paginagrootteformulier bevat het scherm automatisch verborgen ingangen voor alle parameters voor niet-paginatie:
<form method="get" action="@linkUrl" class="page-size-form">
@* Preserve all existing query parameters except pageSize and page-related ones *@
@foreach (var param in ViewContext.HttpContext.Request.Query)
{
if (!new[] { "pageSize", "currentPage", "pageToken", "tokenHistory" }
.Contains(param.Key, StringComparer.OrdinalIgnoreCase))
{
<input type="hidden" name="@param.Key" value="@param.Value" />
}
}
@* Reset to page 1 when changing page size *@
<input type="hidden" name="currentPage" value="1" />
<select name="pageSize" onchange="this.form.submit()">
<!-- options -->
</select>
</form>
Dit werkt naadloos over alle JavaScript-modi en alle ViewTypes. U hoeft nooit handmatig query string propagation te beheren.
Upgraden van pre-1.0 versies is eenvoudig, maar er zijn een paar brekende veranderingen om bewust van te zijn.
1. use-htmx is verouderd (maar werkt nog)
Oud:
<paging model="Model" use-htmx="true" />
<paging model="Model" use-htmx="false" />
Nieuw (aanbevolen):
<paging model="Model" js-mode="HTMX" />
<paging model="Model" js-mode="PlainJS" />
2. ViewType.TailwindAndDaisy maakt nu gebruik van volledige DaisyUI componenten
Als u één van de volgende geneesmiddelen gebruikt: ViewType.TailwindAndDaisy en wil pure Tailwind zonder DaisyUI:
Oud gedrag (zuivere staartwind):
<paging model="Model" view-type="TailwindAndDaisy" />
Nieuw (om oud gedrag te krijgen):
<paging model="Model" view-type="Tailwind" />
Blijf gebruiken TailwindAndDaisy als u DaisyUI-componenten gebruikt:
<paging model="Model" view-type="TailwindAndDaisy" />
<!-- Uses btn, join, badge, select, etc. -->
3. HTMX geüpgrade naar 2.0.4
Als u gebruik maakt van HTMX elders in uw toepassing, zorg ervoor dat compatibiliteit met HTMX 2.0.4. De meeste HTMX 1.x code werkt ongewijzigd, maar bekijk de HTMX 2.0 migratiegids voor edge cases.
Stap 1: Update NuGet Pakket
dotnet add package mostlylucid.pagingtaghelper --version 1.0.0
Stap 2: Bekijk uw bestaande code
Zoek uw codebase naar use-htmx attributen:
# PowerShell
Get-ChildItem -Recurse -Include *.cshtml | Select-String "use-htmx"
# Bash/Git Bash
grep -r "use-htmx" --include="*.cshtml" .
Stap 3: Bijwerken naar js-modus (aanbevolen)
Vervangen use-htmx met js-mode:
- <paging model="Model" use-htmx="true" htmx-target="#results" />
+ <paging model="Model" js-mode="HTMX" htmx-target="#results" />
- <paging model="Model" use-htmx="false" />
+ <paging model="Model" js-mode="PlainJS" />
Stap 4: Review TailwindAndDaisy gebruik
Als je DaisyUI niet geïnstalleerd hebt maar gebruikt TailwindAndDaisy:
- <paging model="Model" view-type="TailwindAndDaisy" />
+ <paging model="Model" view-type="Tailwind" />
Stap 5: Test grondig
Voer uw toepassing en test:
Eenmaal gemigreerd, overwegen deze nieuwe kenmerken aan te nemen:
Lokalisatie:
<paging
model="Model"
language="@CultureInfo.CurrentUICulture.TwoLetterISOLanguageName" />
Continuation Pager (als u NoSQL gebruikt):
<continuation-pager
model="Model"
htmx-target="#results-container"
show-page-number="true" />
NoJS-modus (voor toegankelijkheid):
<paging model="Model" js-mode="NoJS" />
De bibliotheek bevat een uitgebreide demo applicatie met alle functies. U kunt het lokaal uitvoeren of bekijken op de demo site (binnenkort).
Het uitvoeren van de Demo Lokaal:
git clone https://github.com/scottgal/mostlylucid.pagingtaghelper.git
cd mostlylucid.pagingtaghelper/mostlylucid.pagingtaghelper.sample
dotnet run
Navigeren naar https://localhost:5001 om te onderzoeken:
Elke demo bevat:
Versie 1.0.0 is een belangrijke mijlpaal voor de PagingTagHelper bibliotheek. Wat begon als een eenvoudige werkbehoefte is geëvolueerd tot een uitgebreide, productie-ready paginatie oplossing die handvatten:
De bibliotheek is getest met 1.7k+ downloads en is klaar voor productie. Alle 106 unit tests slagen, en de uitgebreide demo applicatie toont gebruikspatronen in de echte wereld.
Toekomstige verbeteringen die ik overweeg:
Installeren via NuGet:
dotnet add package mostlylucid.pagingtaghelper --version 1.0.0
Bekijk de documentatie:
Vragen, feedback of bijdragen? Open een probleem op GitHub of contacteer op Twitter @scottgal.
Gelukkige pagineren!
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.