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

<datetime class="hidden">2025-11-07T19:12</datetime>

<!--category-- Nuget, ASP.NET Core, HTMX, Alpine.js, Javascript, TagHelper, PagingTagHelper -->
> 来之不易,即将到来 [追踪GitHub! ](https://github.com/scottgal/mostlylucid.pagingtaghelper).

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

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

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

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

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

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

[![Nuget 元数](https://img.shields.io/nuget/v/mostlylucid.pagingtaghelper.svg)](https://www.nuget.org/packages/mostlylucid.pagingtaghelper)
[![Nuget 元数](https://img.shields.io/nuget/dt/mostlylucid.pagingtaghelper.svg)](https://www.nuget.org/packages/mostlylucid.pagingtaghelper)

[TOC]

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

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

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

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

```mermaid
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`:

```csharp
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}

```csharp
[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ñ"{ MSSK12}

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

```mermaid
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 视图中 @, @ 使用续序呼叫器简单@ : @

```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>$@product.Price.ToString("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}你就可以完全忽略象征性的历史\:}*

```razor
<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):#

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

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

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

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

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

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

```html
<!-- 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. -->
```

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

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

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

**为何如此重要?**

宇宙 DB 示例*:

```csharp
// 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 自动参数保存确保符号总是与原始查询上下文一起使用@.}

---


## 本地化支持 @{#_localization@-_Support_}

现代应用软件为全球受众服务 @, 且弹射控制器需要使用您的用户的语音@' 语言_. 版本#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/`.

### 本地化使用量 @{#_localization@-_usage}}

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

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

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

```html
<!-- 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\ {}

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

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

```razor
@{
    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

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

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

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

```html
<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 模式的完整解析@: @

```mermaid
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})**

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

重新命名@: @ {}

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

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

**2.HTMX与阿尔卑斯山模式**

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

重新命名@: @ {}

```html
<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.高山模式**

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

重新命名@: @ {}

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

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

**@ 4. 普通JS 模式**

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

重新命名@: @ {}

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

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

```razor
@Html.PageSizeOnchangeSnippet()
```

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

**5. noJS 模式**

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

重新命名@: @ {}

```html
<!-- 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 @{#_migration-}来自 <-\iuse}-Qhtmx%}}

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

```razor
<!-- 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` 清晰度属性@: @%

```razor
<!-- 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`:

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

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

```html
<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-}%mode@}

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

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

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

1. **导航使用锁定链接**# ,# 不是按钮 @:#

```html
<a href="/Products?page=2" class="pager-button">Next ›</a>
```

2. **页面大小选择器是一个窗体**:

```html
<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 模式和视图类型**.

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

```csharp
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 参数的隐藏输入@:}

```razor
<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` 还在工作 )**

旧的:

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

新建 ( 推荐@): @

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

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

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

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

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

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

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

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

```razor
<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移民指南](https://htmx.org/migration-guide-htmx-1/) 用于边缘情况@. @%

### 斯捷步-B-Step移徙

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

```bash
dotnet add package mostlylucid.pagingtaghelper --version 1.0.0
```

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

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

```bash
# 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`:

```diff
- <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`:

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

**步骤 @5:_# 彻底测试**

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

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

### 要通过的新特点

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

**本地化@: @%**

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

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

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

**NoJS 模式@( @ for access**

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

---


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

图书馆包含一个全面的演示应用程序,显示所有功能@. 您可以在本地运行或查看 [演示站点](https://paging-demo.mostlylucid.net) 即将到来

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

```bash
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 @ :+% 安裝

```bash
dotnet add package mostlylucid.pagingtaghelper --version 1.0.0
```

检查文档@: @%

- [GitHub 仓库](https://github.com/scottgal/mostlylucid.pagingtaghelper)
- [NuGet 软件包](https://www.nuget.org/packages/mostlylucid.pagingtaghelper)
- [全部文件齐全](https://github.com/scottgal/mostlylucid.pagingtaghelper/tree/main/docs)

在 GitHub 上打开一个问题, [-=YTET -伊甸园字幕组=- 翻译:](https://twitter.com/scottgal).

玩得开心吗?