asp.net mvc 自定义Pager实现分页
Intro
一个WEB应用程序中经常会用到数据分页,本文将实现一个简单通用的分页组件,包含一个 PagerModel
(用来保存页码信息),一个 HtmlHelper
的 Pager
扩展方法和一个 PagedListModel<T>
分页数据模型。
pager效果图如下:
PagerModel 分页模型
PagerModel 用来保存分页信息,代码实现如下:
/// <summary>
/// PagerModel 分页模型
/// </summary>
public class PagerModel
{
public int PageIndex { get; set; } public int PageSize { get; set; } public int PageCount { get; private set; } public int TotalCount { get; set; } public PagerModel(int totalCount)
{
PageIndex = ;
PageSize = ;
TotalCount = totalCount;
PageCount = Convert.ToInt32(Math.Ceiling(TotalCount * 1.0 / PageSize));
} public PagerModel(int pageSize, int totalCount)
{
PageIndex = ;
PageSize = pageSize;
TotalCount = totalCount;
PageCount = Convert.ToInt32(Math.Ceiling(TotalCount * 1.0 / PageSize));
} public PagerModel(int pageIndex, int pageSize, int totalCount)
{
PageIndex = pageIndex;
PageSize = pageSize;
TotalCount = totalCount;
PageCount = Convert.ToInt32(Math.Ceiling(TotalCount * 1.0 / PageSize));
}
}
PagerModel
/// <summary>
/// PagerModel 分页模型
/// </summary>
public class PagerModel
{
public int PageIndex { get; set; } public int PageSize { get; set; } public int PageCount { get; private set; } public int TotalCount { get; set; } public PagerModel(int totalCount)
{
PageIndex = 1;
PageSize = 10;
TotalCount = totalCount;
PageCount = Convert.ToInt32(Math.Ceiling(TotalCount * 1.0 / PageSize));
} public PagerModel(int pageSize, int totalCount)
{
PageIndex = 1;
PageSize = pageSize;
TotalCount = totalCount;
PageCount = Convert.ToInt32(Math.Ceiling(TotalCount * 1.0 / PageSize));
} public PagerModel(int pageIndex, int pageSize, int totalCount)
{
PageIndex = pageIndex;
PageSize = pageSize;
TotalCount = totalCount;
PageCount = Convert.ToInt32(Math.Ceiling(TotalCount * 1.0 / PageSize));
}
}
Pager扩展方法
Pager扩展方法 可根据自己的需求进行定制话实现,Pager扩展方法需要一个PagerModel类型的参数来生成页码,我这里是用的bootstrap的样式来做的分页,整个系统用的是同一个样式的分页所以把样式直接写死在代码里了。
Pager这里的代码重构做的不是太好:
- 样式直接写死,前端不好维护
/// <summary>
/// PagerHelper 分页帮助类
/// </summary>
public static class PagerHelper
{
public static MvcHtmlString Pager(this HtmlHelper helper, PagerModel pager)
{
StringBuilder sbHtmlText = new StringBuilder();
sbHtmlText.Append("<div style=\"text-align:center\"><nav><ul class=\"pagination\">");
if (pager.PageIndex <= )
{
sbHtmlText.Append("<li class=\"disabled\"><a href=\"javascript:void()\" aria-label=\"Previous\"><span aria-hidden=\"true\">«</span></a></li>");
}
else
{
sbHtmlText.AppendFormat("<li><a href=\"javascript:loadData(1)\" aria-label=\"1\"><span aria-hidden=\"true\">«</span></a></li>", pager.PageIndex - );
sbHtmlText.AppendFormat("<li><a href=\"javascript:loadData({0})\">{0}</a></li>", pager.PageIndex - );
}
sbHtmlText.AppendFormat("<li class=\"active\"><a href=\"javascript:void()\">{0}<span class=\"sr-only\">(current)</span></a></li>", pager.PageIndex);
if (pager.PageIndex >= pager.PageCount)
{
sbHtmlText.Append("<li class=\"disabled\"><a href=\"javascript:void()\" aria-label=\"Next\"><span aria-hidden=\"true\">»</span></a></li>");
}
else
{
sbHtmlText.AppendFormat("<li><a href=\"javascript:loadData({0})\">{0}</a></li>", pager.PageIndex + );
sbHtmlText.AppendFormat("<li><a href=\"javascript:loadData({0})\" aria-label=\"Next\"><span aria-hidden=\"true\">»</span></a></li>", pager.PageIndex + );
}
sbHtmlText.Append("</ul></nav>");
sbHtmlText.AppendFormat("<div><span>每页有<strong>{0}</strong>条数据,一共有<strong>{1}</strong>页,总计<strong>{2}</strong>条数据</span></div></div>", pager.PageSize, pager.PageCount, pager.TotalCount);
return MvcHtmlString.Create(sbHtmlText.ToString());
} public static MvcHtmlString Pager(this HtmlHelper helper, PagerModel pager, Func<int, string> onPageChange)
{
StringBuilder sbHtmlText = new StringBuilder();
sbHtmlText.Append("<div style=\"text-align:center\"><nav><ul class=\"pagination\">");
if (pager.PageIndex <= )
{
sbHtmlText.Append("<li class=\"disabled\"><a href=\"javascript:void()\" aria-label=\"Previous\"><span aria-hidden=\"true\">«</span></a></li>");
}
else
{
sbHtmlText.AppendFormat("<li><a href=\"{0}\" aria-label=\"Previous\"><span aria-hidden=\"true\">«</span></a></li>", onPageChange(pager.PageIndex - ));
sbHtmlText.AppendFormat("<li><a href=\"{0}\">{1}</a></li>", onPageChange(pager.PageIndex - ), pager.PageIndex - );
}
sbHtmlText.AppendFormat("<li class=\"active\"><a href=\"javascript:void()\">{0}<span class=\"sr-only\">(current)</span></a></li>", pager.PageIndex);
if (pager.PageIndex >= pager.PageCount)
{
sbHtmlText.Append("<li class=\"disabled\"><a href=\"javascript:void()\" aria-label=\"Next\"><span aria-hidden=\"true\">»</span></a></li>");
}
else
{
sbHtmlText.AppendFormat("<li><a href=\"{0}\">{1}</a></li>", onPageChange(pager.PageIndex+),pager.PageIndex + );
sbHtmlText.AppendFormat("<li><a href=\"{0}\" aria-label=\"Next\"><span aria-hidden=\"true\">»</span></a></li>", onPageChange(pager.PageIndex + ));
}
sbHtmlText.Append("</ul></nav>");
sbHtmlText.AppendFormat("<div><span>每页有<strong>{0}</strong>条数据,一共有<strong>{1}</strong>页,总计<strong>{2}</strong>条数据</span></div></div>", pager.PageSize, pager.PageCount, pager.TotalCount);
return MvcHtmlString.Create(sbHtmlText.ToString());
}
}
PagerHelper
/// <summary>
/// PagerHelper 分页帮助类
/// </summary>
public static class PagerHelper
{
public static MvcHtmlString Pager(this HtmlHelper helper, PagerModel pager)
{
StringBuilder sbHtmlText = new StringBuilder();
sbHtmlText.Append("<div style=\"text-align:center\"><nav><ul class=\"pagination\">");
if (pager.PageIndex <= 1)
{
sbHtmlText.Append("<li class=\"disabled\"><a href=\"javascript:void()\" aria-label=\"Previous\"><span aria-hidden=\"true\">«</span></a></li>");
}
else
{
sbHtmlText.AppendFormat("<li><a href=\"javascript:loadData({0})\" aria-label=\"Previous\"><span aria-hidden=\"true\">«</span></a></li>", pager.PageIndex - 1);
sbHtmlText.AppendFormat("<li><a href=\"javascript:loadData({0})\">{0}</a></li>", pager.PageIndex - 1);
}
sbHtmlText.AppendFormat("<li class=\"active\"><a href=\"javascript:void()\">{0}<span class=\"sr-only\">(current)</span></a></li>", pager.PageIndex);
if (pager.PageIndex >= pager.PageCount)
{
sbHtmlText.Append("<li class=\"disabled\"><a href=\"javascript:void()\" aria-label=\"Next\"><span aria-hidden=\"true\">»</span></a></li>");
}
else
{
sbHtmlText.AppendFormat("<li><a href=\"javascript:loadData({0})\">{0}</a></li>", pager.PageIndex + 1);
sbHtmlText.AppendFormat("<li><a href=\"javascript:loadData({0})\" aria-label=\"Next\"><span aria-hidden=\"true\">»</span></a></li>", pager.PageIndex + 1);
}
sbHtmlText.Append("</ul></nav>");
sbHtmlText.AppendFormat("<div><span>每页有<strong>{0}</strong>条数据,一共有<strong>{1}</strong>页,总计<strong>{2}</strong>条数据</span></div></div>", pager.PageSize, pager.PageCount, pager.TotalCount);
return MvcHtmlString.Create(sbHtmlText.ToString());
}
}
利用 Func<> 简单重构了一下代码,可以自定义翻页事件
public static MvcHtmlString Pager(this HtmlHelper helper, PagerModel pager, Func<int, string> onPageChange)
{
StringBuilder sbHtmlText = new StringBuilder();
sbHtmlText.Append("<div style=\"text-align:center\"><nav><ul class=\"pagination\">");
if (pager.PageIndex <= 1)
{
sbHtmlText.Append("<li class=\"disabled\"><a href=\"javascript:void()\" aria-label=\"Previous\"><span aria-hidden=\"true\">«</span></a></li>");
}
else
{
sbHtmlText.AppendFormat("<li><a href=\"{0}\" aria-label=\"Previous\"><span aria-hidden=\"true\">«</span></a></li>", onPageChange(pager.PageIndex - 1));
sbHtmlText.AppendFormat("<li><a href=\"{0}\">{1}</a></li>", onPageChange(pager.PageIndex - 1), pager.PageIndex - 1);
}
sbHtmlText.AppendFormat("<li class=\"active\"><a href=\"javascript:void()\">{0}<span class=\"sr-only\">(current)</span></a></li>", pager.PageIndex);
if (pager.PageIndex >= pager.PageCount)
{
sbHtmlText.Append("<li class=\"disabled\"><a href=\"javascript:void()\" aria-label=\"Next\"><span aria-hidden=\"true\">»</span></a></li>");
}
else
{
sbHtmlText.AppendFormat("<li><a href=\"{0}\">{1}</a></li>", onPageChange(pager.PageIndex+1),pager.PageIndex + 1);
sbHtmlText.AppendFormat("<li><a href=\"{0}\" aria-label=\"Next\"><span aria-hidden=\"true\">»</span></a></li>", onPageChange(pager.PageIndex + 1));
}
sbHtmlText.Append("</ul></nav>");
sbHtmlText.AppendFormat("<div><span>每页有<strong>{0}</strong>条数据,一共有<strong>{1}</strong>页,总计<strong>{2}</strong>条数据</span></div></div>", pager.PageSize, pager.PageCount, pager.TotalCount);
return MvcHtmlString.Create(sbHtmlText.ToString());
}
关于样式修改维护的问题,找到一种解决方案,可以将分页代码的样式封装在一个分部视图partial,在需要分页的页面视图,引用这个分部视图并且将分页模型信息 PagerModel 传递给这个分部视图
PagedListModel 分页数据模型
PagedListModel 用来封装返回到视图 View 的数据和 分页模型 PagerModel,实现代码如下
/// <summary>
/// 数据分页模型
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
public class PagedListModel<T> where T : class, new()
{
public List<T> Data { get; set; } public PagerModel Pager { get; set; }
}
PagedListModel
public class PagedListModel<T> where T : class, new()
{
public List<T> Data { get; set; } public PagerModel Pager { get; set; }
}
控制器数据处理
控制器处理代码如下:
search 是一个包含了 PageIndex 和 PageSize 的请求参数
int rowsCount = ;
try
{
List<Models.BlockEntity> blockList = BusinessHelper.BlockEntityHelper.GetPagedList(search.PageIndex, search.PageSize, out rowsCount, whereLambda, b => b.BlockTime, false);
PagerModel pager = new PagerModel(search.PageIndex, search.PageSize, rowsCount);
PagedListModel<Models.BlockEntity> dataList = new PagedListModel<Models.BlockEntity>() { Pager = pager, Data = blockList };
return View(dataList);
}
catch (Exception ex)
{
logger.Error(ex);
throw;
}
Controller
int rowsCount = 0;
try
{
List<Models.BlockEntity> blockList = new Business.BLLBlockEntity().GetPagedList(search.PageIndex, search.PageSize, out rowsCount, whereLambda, b => b.BlockTime, false);//记录日志
PagerModel pager = new PagerModel(search.PageIndex, search.PageSize, rowsCount);//定义Pager Model
PagedListModel<Models.BlockEntity> dataList = new PagedListModel<Models.BlockEntity>() { Pager = pager, Data = blockList };//定义返回到 View 的 PagedListModel
return View(dataList);
}
catch (Exception ex)
{
logger.Error(ex);//记录日志
throw;
}
页面处理
首先在页面顶部声明 model 模型
@model PagedListModel<Models.BlockEntity>
在页面上遍历数据
@foreach (Models.BlockEntity item in Model.Data)
在需要添加分页信息的地方使用 HtmlHelper 的 Pager 扩展方法
@Html.Pager(Model.Pager)
View代码示例
@model PagedListModel<Models.BlockEntity>
<table class="table table-hover">
<thead>
<tr>
<th>黑名单类型</th>
<th>黑名单内容</th>
<th>拉入黑名单时间</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
@foreach (Models.BlockEntity item in Model.Data)
{
string className = "bg-success";
if (!item.IsActive)
{
className = "bg-danger";
}
<tr class="@className">
<td>
@item.BlockType.TypeName
</td>
<td>
@item.BlockValue
</td>
<td>
@item.BlockTime
</td>
<td>
@if (item.IsActive)
{
<span>启用</span>
}
else
{
<span>禁用</span>
}
</td>
<td>
@if (item.IsActive)
{
<button type="button" class='btn btn-warning' onclick="UpdateStatus('@item.BlockId', '@item.BlockValue',-1,this)">禁用</button>
}
else
{
<button type="button" class='btn btn-warning' onclick="UpdateStatus('@item.BlockId','@item.BlockValue',1,this)">启用</button>
}
<button type="button" class="btn btn-danger" onclick="DeleteEntity('@item.BlockId','@item.BlockValue',this)">删除</button>
</td>
</tr>
}
</tbody>
</table>
@Html.Pager(Model.Pager)