MvcPager (Webdiyer) 是 ASP.NET MVC 經典分頁套件,支援同步分頁、AJAX 非同步分頁、自訂樣式模板,NuGet 安裝:Install-Package MvcPager。
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime CreateTime { get; set; }
}
public class ArticleListViewModel
{
public PagedList<Article> Articles { get; set; }
public string Keyword { get; set; }
}
public class ArticleController : Controller
{
private readonly IArticleRepository _repo;
public ArticleController(IArticleRepository repo) => _repo = repo;
// 同步分頁
public async Task<ActionResult> Index(int page = 1, string keyword = "")
{
int pageSize = 10;
var (items, total) = await _repo.SearchAsync(keyword, page, pageSize);
var pagedList = new PagedList<Article>(items, page, pageSize) { TotalItemCount = total };
return View(new ArticleListViewModel { Articles = pagedList, Keyword = keyword });
}
// AJAX 部分視圖回傳
public async Task<ActionResult> _ArticleList(int page = 1, string keyword = "")
{
int pageSize = 10;
var (items, total) = await _repo.SearchAsync(keyword, page, pageSize);
var pagedList = new PagedList<Article>(items, page, pageSize) { TotalItemCount = total };
return PartialView("_ArticleList", new ArticleListViewModel { Articles = pagedList, Keyword = keyword });
}
}
@model ArticleListViewModel
@using Webdiyer.WebControls.Mvc
<div class="container">
@* 搜尋表單 *@
@using (Html.BeginForm("Index", "Article", FormMethod.Get, new { id = "searchForm" }))
{
<div class="input-group mb-3">
@Html.TextBox("keyword", Model.Keyword, new { @class = "form-control", placeholder = "輸入關鍵字..." })
<span class="input-group-btn">
<button type="submit" class="btn btn-primary">搜尋</button>
</span>
</div>
}
@* 文章列表容器 (AJAX 更新目標) *@
<div id="articleList">
@{ Html.RenderPartial("_ArticleList", Model); }
</div>
@* AJAX 分頁導航 *@
@Ajax.Pager(Model.Articles, new PagerOptions
{
PageIndexParameterName = "page",
HttpMethod = HttpMethod.Get,
AjaxOptions = new AjaxOptions
{
UpdateTargetId = "articleList", // 更新容器 ID
LoadingElementId = "loadingSpinner", // 可選:載入中動畫
OnSuccess = "onPageLoaded" // 可選:完成回呼
},
// 樣式自訂 (Bootstrap 4/5)
ContainerTagName = "nav",
CssClass = "pagination justify-content-center",
CurrentPagerItemTemplate = "<li class=\"page-item active\"><a class=\"page-link\" href=\"#\">{0}</a></li>",
DisabledPagerItemTemplate = "<li class=\"page-item disabled\"><span class=\"page-link\">{0}</span></li>",
PagerItemTemplate = "<li class=\"page-item\"><a class=\"page-link\" href=\"{1}\">{0}</a></li>",
PrevPageText = "« 上一頁",
NextPageText = "下一頁 »",
FirstPageText = "首頁",
LastPageText = "末頁",
NumericPagerItemCount = 5
})
<div id="loadingSpinner" class="text-center d-none"><span class="spinner-border"></span></div>
</div>
@section Scripts {
<script>
function onPageLoaded() {
// 換頁後捲動至列表頂部
$('html, body').animate({ scrollTop: $('#articleList').offset().top - 100 }, 300);
}
</script>
}
@model ArticleListViewModel
<table class="table table-striped table-hover">
<thead>
<tr><th>ID</th><th>標題</th><th>建立時間</th></tr>
</thead>
<tbody>
@foreach (var item in Model.Articles)
{
<tr>
<td>@item.Id</td>
<td>@Html.DisplayFor(m => item.Title)</td>
<td>@item.CreateTime.ToString("yyyy/MM/dd HH:mm")</td>
</tr>
}
</tbody>
</table>
@* 同步分頁備援 (JS 失效時仍可運作) *@
@if (Request.IsAjaxRequest() == false)
{
@Html.Pager(Model.Articles, new PagerOptions
{
PageIndexParameterName = "page",
ContainerTagName = "nav",
CssClass = "pagination justify-content-center",
// ... 樣式設定同上
})
}
Q: AJAX 分頁換頁後 URL 不變?
A: 這是預期行為 (局部更新)。若需 URL 同步,可在 `OnSuccess` 回呼中使用 `history.pushState` 更新瀏覽器網址列。
Q: 如何整合到 ASP.NET Core?
A: MvcPager 原版僅支援 MVC 5。Core 專案建議改用 X.PagedList.Mvc.Core 或自行實作 TagHelper (參考本系列其他文章)。
善用 MvcPager 靈活的模板系統,能快速產出符合設計規範、體驗流暢的分頁介面,是 MVC 專案的利器。