Paging TagHelfer v1.0.0:企业企管 @ -对现代 ASP}.NET核心的重新缓冲 (中文 (Chinese Simplified))

Paging TagHelfer v1.0.0:企业企管 @ -对现代 ASP}.NET核心的重新缓冲

Friday, 07 November 2025

//

15 minute read

来之不易,即将到来 追踪GitHub! .

这只是为了向你们展示我在这个控制器上的进展... ...#!_It'_Ill是值得等待的#MS K2}

一. 导言导言 导言 导言 导言

在经过数月的进化和来自社群的宝贵反馈后, @(5.7k+下载@!),I'm 兴奋地宣布PageTagHelfer图书馆已进入版本{1.0.0.这是'}这只是一个拼接数字的翻版{MS K6它代表了图书馆完全成熟的功能,具有适合真正“-world},生产应用程序}MSC9}

如果你一直关注这个系列 , ưμ㼯A添加“,” 可排序排序标题, 并提取 页面大小控件“.”版本“1.0.0”将我们学到的所有东西都带走,并添加了关键的企业特征“MSC3”

  • 继续调制 用于 noSQL 数据库 : @(Cmos DB,DynamoDB,Azure表格存储@)
  • 多语种本地化 支持“8”的语言
  • 弹性 JavaScript 模式 从 HTMX 到零@ - @ JavaScript
  • 纯粹反向视图 没有DisaudisUI依赖性
  • 智能 URL 参数保护 横贯所有导航
  • HTMX 2.0.4 具有后向兼容性升级

让'沉入其中的每一个特征中, 看看他们如何合作 创造出真正灵活的页码解决方案

Nuget 元数 Nuget 元数

继续调整调控 {# @csurvation\ -}token@token_-#pagination=}

与 SQL 数据库一起,传统页式工作非常出色,您可以很容易地使用 SKIP 和 TAKE @.}但是如果你在像宇宙 DB ,Dynamoddab,或Azure表格存储@?这样的 NoSQL 数据库中工作,这些数据库会怎样呢? 续序号.

理解 Token@ - @ 基于 Pagination @ MS K1_ 了解 @ k2 @ token @ I-} (基于 @ MPK4 @ pagrination @ })

这里“ ' @% 1” 表示继续象征性的外观与传统的 page@ MS K1} 有何不同?

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

传统Paging:

  • 您精确指定要检索哪些记录@ ( @ OFFSET+/ @ LIMIT)}
  • 您可以直接跳转到任何页面
  • 数据库必须扫描前所有记录

调制解密@ - @ 基于 Pageing+:}

  • 数据库返回一个不透明的标牌,代表 "}在哪个位置可以继续\ MPK1\
  • Token 格式是数据库@-} 特定且客户端不透明
  • 前向导航是自然的 , 后向导航需要象征性的历史

继续页面执行@{# @csurvation @-_pager}-#implementation=}

新的 <continuation-pager> 标签帮助工具使执行标记@ - @ 基于 passion 以直截了当 <% MS K1} first,} 创建一个模式来实施 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();
}

此界面是最小的, 但功能强大的@ . @ Let' @%s 看看每个属性都做了些什么 @ MS K2 @ *

  • NextPageToken: 获取下一页的标记 @( 由您的数据库提供@)
  • HasMoreResults:_Boolean 表示是否有更多页面
  • PageSize: 每页的项目
  • CurrentPage: 显示 - 仅用于 UI 的页面编号
  • PageTokenHistory: 字典映射页面编号为用于后向导航的标记@ info: whatsthis
  • ViewType: CSS 框架用于提供

现在让我们来执行一个控制器动作, 模拟宇宙 DB\ - 风格的射程@ MS K2}

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

此功能显示象征历史如何允许后向导航@ . @ 没有它 @ MS K1 @ 继续象征性的外观只会支持 @ MPK2\ next"}按键=.}通过维护页面的字典 <-\to MSQK6}token 映射@,}我们既可以支持“ MSKO8” prepvied\ " ,也可以支持 &"_ nextñ"

这里“'”是象征性积累的可视化流 @:

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

在您的 Razor 视图中 @, @ 使用续序呼叫器简单@ : @

@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>

标签助手自动@: @%

  • 将象征性历史序列化为查询参数
  • 以合适的符号构建导航 URL
  • 禁用%" @ preview@ "} 当页面@ I1 @
  • 禁用@" @ next @ "}当 HasMoreResults 是假的
  • 保存所有其它查询参数@( @search=,}过滤器 @,}等{.)}

后向导航的脚本历史 @ {# @ token@ MS K1_ history @ MPK2 @

象征性历史方法的天才是,它“'”完全是可选的“MS K1” 如果你只需要 “"”Next‘"}导航“(’infinite pollic,” 例如“MSSK6}你就可以完全忽略象征性的历史:}*

<continuation-pager
    model="Model"
    enable-token-accumulation="false"
    show-page-number="false" />

仅此设置一个没有页面指示器或历史管理的“"@ next @ "Q” 按钮@ MS K2@

对于完整导航 < , },象征性历史将自动序列化为 JSON 在查询字符串{. > 中的 JSonson 。\ MS K2 _ 这里>'_ URL 看上去像什么?

/Products?currentPage=3&pageSize=25&pageToken=abc123&tokenHistory=%7B%221%22%3A%22xyz789%22%2C%222%22%3A%22abc123%22%7D

缩略 tokenHistory 参数包含编码的字典@,}使后向导航无缝 *.

编号 导航 = {# 数 =\ MS K1 page} - Navigation =}

续用传呼器最重要的UX改进之一是 编号页面按钮@._Q}在您往前游时,请按下鼠标显示所有访问过的页面的可点击页码@:}

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)

这将提供传统的页码 UX, 同时维护 Sign@ - @ basim 后端架构@ I.} 每个被访问的页面的执行存储牌\ MS K2} 允许直接浏览先前访问过的任何网页@ MPK3}

限制历史增长+:

防止无约束内存使用@, @% 设置 max-history-pages @(_default :}20):#

<continuation-pager
    model="Model"
    max-history-pages="50"
    show-page-number="true" />

当限制达到@,}最老的标牌自动缩略@ .}

查询参数保存 @{#Qquery @MS K2_parameter@-_preservation}

这是继续执行 pcalr 的最重要特点 @. @%

继续的符號只有使用相同的查詢上下文@ (_ filters\ @ MS K1}color , 搜尋)}來產生它們才有效 使用不同查詢參數的標籤會傳回不正確的数据或完全失敗%.}

继续 pager 自动保存所有查询参数, 除了它自己的@ : @

<!-- URL with filters -->
/Products?category=electronics&brand=acme&minPrice=100

<!-- After clicking Next -->
/Products?category=electronics&brand=acme&minPrice=100&currentPage=2&pageToken=xyz123&tokenHistory={...}

<!-- All filters preserved! Token is valid because query context matches. -->

如果需要, 您可以禁用此行为@ : @

<continuation-pager
    model="Model"
    preserve-query-parameters="false" />

但是,这是 强烈不鼓励 除非您% ' @ re绝对确定您的标牌don'@ t取决于查询的上下文@.}

为何如此重要?

宇宙 DB 示例*:

// 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!
);

继续 paller@ ' @%s 自动参数保存确保符号总是与原始查询上下文一起使用@.}


本地化支持 @

现代应用软件为全球受众服务 @, 且弹射控制器需要使用您的用户的语音@' 语言_. 版本#1.0.0 包括设置在库中的全面本地化支持}=.

以语言制作的{# -in- 语言=}

译为“8” 语言的图书馆船

-=YTET -伊甸园字幕组=- 翻译: |------|----------| | en |英语 @(}默认=)}|{ | de {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080} | es 西班牙语: ( ESPAñol MS K2 NSK3 | fr -=YTET -伊甸园字幕组=- 翻译: | it |意大利语 @( @意大利语#)}@| | pt 葡萄牙语: @( @Portuguès @)|# | ja |日语 @()}#|日本语 @ | zh-Hans @|中文简化@()}#|

全部文本已本地化@ , @ 包括 @ MS K1} @

  • 上一个@ / @ next @ / @ First @ MS K2 @ 最后一个按钮标签
  • Z 项的简略文字\ (" 显示 X 到 Y+")\
  • 无障碍的ARIA标签
  • 页面大小标签 #% ("# 每页项目@")}

本地化系统由 .resx 资源文件@,使您能够轻松添加您的语言=%.}所有的资源文件都在 mostlylucid.pagingtaghelper/Resources/.

本地化使用量 @

使用本地化是直截了当的@. @ 只要添加 language 属性@: @%

<paging
    model="Model"
    language="de"
    show-summary="true"
    first-last-navigation="true" />

这将使所有文本都用 German :}( 德语) 成为文字

<!-- 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>

对于基于用户首选项的动态语言切换 <% , 设置您的控制器中的语言\ MS K1\

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

然后在您看来“, ” 创建一个语言选择器@:

@{
    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" />

您也可以在其它元素本地化的好处中, 覆盖单个文本字符串@: @% 1

<paging
    model="Model"
    language="ja"
    previous-page-text="戻る"
    next-page-text="次へ"
    summary-template="全{TotalItems}件中 {StartItem}~{EndItem}件を表示" />

缩略 PagingLocalizer 如果您通过了无效语言代码@,}它会自然地返回到英语\ .}

对于 HTMX 整合 < , } 你'\ {将希望保存所有请求中的语言\ MS K2\ *

<script>
    htmx.on('htmx:configRequest', function(event) {
        if (event.detail.path.includes('/Products')) {
            event.detail.parameters.language = '@selectedLanguage';
        }
    });
</script>

这样可以确保 HTMX 部分视图更新保持所选语言@.


JavaScript 模式 @ {# @ javastricte@ MS K1_ modes @ MPK2 @

V1.0.0中最重要的改进之一是引入了灵活的 JavaScript 模式@ . 前情提要 @ MS K2你有一个布林选择@: use-htmx="true" 或 use-htmx="false". 现在您有五种不同的模式 @, 每种都为不同情景优化了=.

可用的模式 @ {# @ option\ MS K1 @ modes@ } @

下面是 JavaScript 模式的完整解析@: @

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]

让我们在动作中看到每个模式@ : @

1.#HTMX 模式 @(_Default})

<paging
    model="Model"
    js-mode="HTMX"
    htmx-target="#results-container" />

重新命名@: @

<button hx-get="/Products?page=2" hx-target="#results-container" hx-swap="outerHTML">
    Next ›
</button>

这是现代 ASP=.}NET Core applications.}推荐的模式

2.HTMX与阿尔卑斯山模式

<paging
    model="Model"
    js-mode="HTMXWithAlpine"
    htmx-target="#results-container" />

重新命名@: @

<button
    x-data
    hx-get="/Products?page=2"
    hx-target="#results-container"
    hx-swap="outerHTML">
    Next ›
</button>

与 Alpine 组合用于导航的 HTMX 和 Alpino @ . @ jjs 以附加客户端@ MS K1} 侧面交互性\ .} 当您需要反应式 UI 元素时, 请使用此选项。

3.高山模式

<paging
    model="Model"
    js-mode="Alpine" />

重新命名@: @

<button
    x-data
    @click="window.location.href = '/Products?page=2'">
    Next ›
</button>

纯Alpine.js 没有 HTMXMS K1}有用 当您已经使用 Alpine}.Js 但不要HTMX依赖性时

@ 4. 普通JS 模式

<paging
    model="Model"
    js-mode="PlainJS" />

重新命名@: @

<button onclick="window.location.href = '/Products?page=2'">
    Next ›
</button>

没有框架依赖性@, 仅是 Vanilla JavaScript @. 此模式还包括一个用于更改页面大小的助手@ :}

@Html.PageSizeOnchangeSnippet()

这将输入所需的 JavaScript , 用于在不使用 HTMX @ . 的情况下处理页面大小下调更改

5. noJS 模式

<paging
    model="Model"
    js-mode="NoJS" />

重新命名@: @

<!-- 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>

零 JavaScript 需要@. @sperfect

  • 无障碍要求
  • 渐进增强设想方案
  • JavaScript 禁用的环境
  • SEO-}关键頁面,您希望在哪里爬行? -}#方便的导航

这个体系的美丽之处在于 所有模式都保存您现有的查询参数. 您是否通过分类@ MS K2 搜索 @ , 或排序@ I, 您的状态自动维持@ MPK5

从使用移民@-ñáhtmx @

后向兼容性=,旧 use-htmx 仍在工作属性@: @%

<!-- 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" -->

但我建议移居到新的世界 js-mode 清晰度属性@: @%

<!-- New syntax (recommended) -->
<paging model="Model" js-mode="HTMX" />
<paging model="Model" js-mode="PlainJS" />

视图类型增强@ {# @ viewtype @ MS K1_ enhancements @ MPK2

版本 @1.0.0 引入了两个重要的 ViewType 添加内容, 涉及常见真实@-}世界情景.

纯粹的尾风 @ {# @ pure@ MS K1} 尾风+}

前情提要 , 如果你想要尾风 CSCS的打字,你得到了 TailwindAndDaisy 使用 DaisiUI 组件的视图@ . @ 如果您已经使用了 DasiUI @ MS K2} 这将非常棒, 如果您想要纯尾风而不使用 DsaisyUI Appliance\ ?

输入 ViewType.Tailwind:

<paging
    model="Model"
    view-type="Tailwind" />

这样只能使用标准的尾风工具类@ : @ {

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

否 无 btn, badge,或 join @ – @ just pleaty Talkwind@ MS K1}这样您就可以完全控制无组成部分库依赖关系的外观设置

比较:

ViewType CSS框架 * 组件库* 使用 case=
TailwindAndDaisy 已经使用 DaisyUI & 的工程
Tailwind +TackwindCSCS+ +None @ +纯斜尾风工程@ #
Bootstrap _Bootstract { }布设构件 @ _Botscrap Projects { {poststractions project {possible_BARBAR_ posities_B拉皮条系构件@MSK4_BRATIONBLA} MS K3}
Plain 嵌入式 CSS 无 @ 没有框架依赖性 *
NoJS -=YTET -伊甸园字幕组=- 翻译:

NoJS 模式 @

缩略 NoJS ViewType 组合零 JavaScript 和普通 CSS 样式@ :

<paging
    model="Model"
    view-type="NoJS"
    show-pagesize="true" />

与其他视图类型的密钥差异@: @%

  1. 导航使用锁定链接# ,# 不是按钮 @:#
<a href="/Products?page=2" class="pager-button">Next ›</a>
  1. 页面大小选择器是一个窗体:
<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>

缩略 onchange="this.form.submit()" 当 JavaScript 有时提供方便@ , @ but the <noscript> 按钮在它“% '” 而非“ MS K1” 时确保完整功能


URL 参数保存@{# @url-_parameter @-}preservation*}

在 page@.}版本 @1.0.0 解决此优雅方式时, 您的过滤器@ ,搜索术语\ , 或排序顺序已丢失。 自动保存所有查询参数, 除了弹射控制@' @%s 自己的参数.

此特性在 正常的呼叫器和继续的按键# ,和横跨# 全部 JavaScript 模式和视图类型.

这里#' @%_ 如何在内部工作@:} @

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

此方法意指:

*假想 {1:} 搜索 \ +} 挂接

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

正在排序 _+ pignation

Initial URL: /Products?orderBy=price&descending=true&page=1
Click Page 3: /Products?orderBy=price&descending=true&page=3

带有过滤器的“ 3:” 继续打印程序

Initial URL: /Products?category=electronics&brand=acme
Click Next: /Products?category=electronics&brand=acme&currentPage=2&pageToken=abc123&tokenHistory={...}

在 {(} noJS mode ). 表格中相同的保存工作 当转换页面大小的窗体,} 视图自动包含所有非{MS K3 pagination 参数的隐藏输入@:}

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

这工作无缝地顺利 全部 JavaScript 模式和所有视图类型. 您不必手动管理查询字符串传播@.


《移民指南》{# migration_ -_ Guide MSSK2

升级前的“-1.0”版本是直截了当的@,}但有一些断裂的更改, 以了解 @.

断开更改

1. use-htmx 还在工作 )

旧的:

<paging model="Model" use-htmx="true" />
<paging model="Model" use-htmx="false" />

新建 ( 推荐@): @

<paging model="Model" js-mode="HTMX" />
<paging model="Model" js-mode="PlainJS" />

2.ViewType.TaillwindandDaisy 现在使用完整的 DisaiUI 组件

如果你使用 ViewType.TailwindAndDaisy 想要纯粹的尾风 没有DaisiU:

旧行为 @ ( @ 纯白尾风@ MS K1 @

<paging model="Model" view-type="TailwindAndDaisy" />

新的“(”以获得旧行为@):

<paging model="Model" view-type="Tailwind" />

继续使用 TailwindAndDaisy 如果您使用 DaisiUI 元件@ :

<paging model="Model" view-type="TailwindAndDaisy" />
<!-- Uses btn, join, badge, select, etc. -->

3.HTMX升级为2.0.4

如果您在应用程序中其他地方使用 HTMX , @,}确保与 HTM X 的兼容性@2.0.4.}大多数HTMX\ 1.x 代码正常工作。 HTMX 2.0移民指南 用于边缘情况@. @%

斯捷步-B-Step移徙

步骤 @1:}更新 NuGet 软件包

dotnet add package mostlylucid.pagingtaghelper --version 1.0.0

步骤“2:”审查您现有的代码

搜索您的代码库 use-htmx 属性@: @%

# PowerShell
Get-ChildItem -Recurse -Include *.cshtml | Select-String "use-htmx"

# Bash/Git Bash
grep -r "use-htmx" --include="*.cshtml" .

步骤“3:”更新到js- mode @(_建议@)}

替换 use-htmx 与 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" />

4: 校验尾风和Daisy的使用情况

如果您没有安装 DaisaiUI , 但正在使用 TailwindAndDaisy:

- <paging model="Model" view-type="TailwindAndDaisy" />
+ <paging model="Model" view-type="Tailwind" />

步骤 @5:_# 彻底测试

运行您的应用程序并测试@: @%

  • 页面导航
  • 页面大小变化
  • HTMX 部分更新@(if 使用HTMX @)
  • 过滤器/搜索保护
  • 移动响应

要通过的新特点

一旦迁移 , 考虑采用这些新功能 :

本地化@: @%

<paging
    model="Model"
    language="@CultureInfo.CurrentUICulture.TwoLetterISOLanguageName" />

使用 NOSQL): 来继续 Pager @ ( @ if

<continuation-pager
    model="Model"
    htmx-target="#results-container"
    show-page-number="true" />

NoJS 模式@( @ for access

<paging model="Model" js-mode="NoJS" />

Dema 应用程序@{# @demo-}应用程序_}

图书馆包含一个全面的演示应用程序,显示所有功能@. 您可以在本地运行或查看 演示站点 即将到来

正在运行本地端的 Demo @ : @

git clone https://github.com/scottgal/mostlylucid.pagingtaghelper.git
cd mostlylucid.pagingtaghelper/mostlylucid.pagingtaghelper.sample
dotnet run

导航至 https://localhost:5001 来探索 @:

  1. 与模型基本对接 - 传统 SQL- 风格传呼
  2. HTMX 整合 - 动态页面更新, 没有全页重新加载
  3. 使用 HTMX 搜索 *- 联合搜索和射程
  4. 普通 CSS -无框架依赖性
  5. 纯粹尾风 - 尾风 CSS 没有DisaiUI
  6. 无 JavaScript -=YTET -伊甸园字幕组=- 翻译:
  7. JavaScript 模式 所有五种联署材料模式都展示了侧面的“-”和“MS K2”
  8. 页面排序 - 带有 HTMX 的可排序信头
  9. 页面排序无 HTMX - 具有全页负载的可排序信头
  10. 带有 HTMX 的页面大小 - 动态页面大小变化
  11. 页面大小无 HTMX - 页面大小及表格提交
  12. 继续页面器 -NoSQL- 风格牌 *-基底射程
  13. 本地化 - 语言选择器

每个演示包含 @: @%

  • 工作源代码
  • 技术解释
  • 与 GitHub 执行链接
  • 用于实验的交互式控件

结论结论

版本“1.0.0”是PagingTagHelfer图书馆的重要里程碑。 “简单的工作要求”始于此,现已演变成一个综合性的“MS K2”制片“--备妥的射程解决方案,可以处理 @: }

  • 传统SQL页数 页:1
  • NOSQL 继续代号显示 对于宇宙 DB ,DynamoDB,等
  • 多语种本地化 供全球受众使用
  • 弹性 JavaScript 模式 从 HTMX 到零@ - @ JavaScript
  • CSS 多个多 CSS框架 从DisaiUI 到纯尾风到无
  • 智能参数保护 横贯所有导航
  • 完全无障碍支持 带有 ARIA 标签和键盘导航

该图书馆已经通过“1.7Qk+下载”测试并准备投入生产使用。 “.}所有 106单位测试都通过了@,,综合演示应用展示显示真实的#-world用法模式*.

什么是' 下一步 @?

未来增强功能 I'm考虑}MS K1

  • 附加的 CSS 框架支持 @ ( @ matirial UIQ,} Bulma)
  • 更多本地化语言 @(#社区捐款欢迎@!)_%
  • Server -side Blazor 元件
  • 增强无障碍环境特点
  • 大型数据集的性能优化

开始

通过 Nuget @ :+% 安裝

dotnet add package mostlylucid.pagingtaghelper --version 1.0.0

检查文档@: @%

在 GitHub 上打开一个问题, -=YTET -伊甸园字幕组=- 翻译:.

玩得开心吗?

Finding related posts...
logo

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