1、引言
在MVC开发中我们经常会对数据进行分页的展示。通过分页我们可以从服务端获取指定的数据来进行展示。这样既节约了数据库查询的时间也节约了网络传输的数据量。在MVC开发中使用的比较多的应该是MVCPager控件。这个控件提供无刷新分页等功能。虽然我们有这么好的控件可以使用,但是我们还是需要通过简单的例子来看一下原始的分页技术的雏形,学习下原始分页的技术实现。
2、简单的分页实现
此处使用T_Products表查询商品数据,然后进行展示。商品类定义如下:
public sealed class Product { public string ProductId { get; set; } public string ProductName { get; set; } public string ProductImage { get; set; } public int Price { get; set; } public string CategoryId { get; set; } public string Description { get; set; } }
我们通过仓储模式来定义数据的存储操作。其接口定义和实现类定义
public interface IProductRepository { /// <summary> /// 获取数据库中全部的商品信息 /// </summary> /// <returns></returns> IQueryable<T_Product> GetAll(int pageIndex, int pageSize, out int total); }
public class ProductRepository : IProductRepository { private DB_ShoppingEntities shoppingEntities = null; public ProductRepository() { this.shoppingEntities = new DB_ShoppingEntities(); } public IQueryable<T_Product> GetAll(int pageIndex, int pageSize, out int total) { total = this.shoppingEntities.T_Product.Count(); return this.shoppingEntities.T_Product.AsQueryable().OrderBy(p => p.Price).Skip((pageIndex - 1) * pageSize).Take(pageSize); } }
通过上面的代码我们清晰的看到我们通过Linq表达式来获取指定页数的数据,当然也获取了当前操作所获取的数据的条数。下面我们需要定义自定义分页帮助类来协助我们构造分页所需的一些信息。定义如下:
/// <summary> /// 分页帮助类 /// </summary> public sealed class MyPager { private int total; //当前页的索引 public int pageIndex { get; set; } //总的页数 public int pageCount { get; set; } public MyPager(int total, int pageSize, int pageIndex) { this.total = total; this.pageIndex = pageIndex; //计算总页数 int result = this.total % pageSize; this.pageCount = result == 0 ? this.total / pageSize : this.total / pageSize + 1; } }
我们可以想一想分页的基本流程。我们客户端发送请求到服务端获取指定的数据。这时候我们将符合条件的数据查询出来以后,返回给客户端即可。但是分页的页码也是需要更新的。这里我们可以将分页的一些信息也一起返回给客户端。然客户端在展示新的数据的同时也更新分页的状态。在这里我们可以将分页的信息封装到一个类里面。这样我们可以重新定义一个类模型将需要返回给客户端的Products和分页信息封装到一起一起发给客户端,这样客户端就可以进行渲染。
/// <summary> /// 带分页功能的产品类别 /// </summary> public sealed class PagedProducts { public IList<Product> Products { get; set; } public MyPager pager { get; set; } }
这时我们来看控制器中的方法。
public class ProductController : Controller { private IProductRepository productRepository = null; //每一页展示的数量 private const int pageSize = 4; public ProductController(IProductRepository productRepository) { this.productRepository = productRepository; } public ViewResult Index(int pageIndex = 1) { PagedProducts pagedProducts = null; IList<Product> list = null; int total = 0; var products = this.productRepository.GetAll(pageIndex, pageSize, out total); if (products != null && products.Count() > 0) { pagedProducts = new PagedProducts(); list = new List<Product>(); foreach (var item in products) { list.Add(new Product { ProductId = item.ProductID, ProductName = item.ProductName, ProductImage = item.ProductImage == null ? "" : item.ProductImage, Price = (int)item.Price, CategoryId = item.CategoryID, Description = item.Description }); } //定义分页对象 pagedProducts.Products = list; pagedProducts.pager = new MyPager(total, pageSize, pageIndex); } return View(pagedProducts); } }
我们定义的pagedProducts包含了Products和pager对象。这样我们在客户端就可以进行渲染。客户端的代码如下:
@model Shopping.Models.PagedProducts @using Shopping.ExtendMethod; @{ Layout = "~/Views/Shared/_Layout.cshtml"; } <style type="text/css"> table { 60%; height:auto; margin:60px auto; border-collapse:collapse; border:0px; } table tr{ text-align:center; height:30px; line-height:30px; } /*设置第一行的样式*/ table tr:first-child { background-color:#cccccc; font-weight:bold; } table tr td { border:1px #565252 solid; } div { 60%; height:30px; margin:20px auto; } div a { line-height:30px; text-align:center; padding:12px; font-size:14px; text-decoration:none; } div .selected { font-weight:bold; font-size:16px; } </style> <table> @if (Model != null && Model.Products.Count > 0) { <tr> <td>编号</td> <td>名称</td> <td>价格</td> </tr> foreach (var item in Model.Products) { <tr> <td>@item.ProductId</td> <td>@item.ProductName</td> <td>@item.Price</td> </tr> } } else { <tr> <td> 当前不存在数据 </td> </tr> } </table> <!--分页--> <div> @Html.MyPagerLink(Model.pager, index => Url.Action("Index", new { pageIndex = index })) </div>
我们看到MyPagerLink方法,这个方法就是我们自定义进行分页的渲染方法。通过服务端传递的分页信息来渲染指定的分页信息进行展示。其代码如下:
/// <summary> /// 定义扩展方法 /// </summary> public static class ExtendMethod { /// <summary> /// 自定义分页扩展方法 /// </summary> /// <param name="htmlHelper"></param> /// <param name="pager">分页对象</param> /// <param name="pageUrl">定义委托,该委托满足给定int类型的参数返回string类型的返回结果</param> /// <returns></returns> public static MvcHtmlString MyPagerLink(this HtmlHelper htmlHelper, MyPager pager, Func<int, string> pageUrl) { StringBuilder result = null; if (pager.pageCount > 0) { result = new StringBuilder(); for (int i = 1; i <= pager.pageCount; i++) { TagBuilder tag = new TagBuilder("a"); //指定页数的链接 tag.MergeAttribute("href", pageUrl(i)); tag.InnerHtml = i.ToString(); if (i == pager.pageIndex) { tag.AddCssClass("selected"); } result.Append(tag.ToString()); } } return MvcHtmlString.Create(result == null ? "" : result.ToString()); } }
我们通过看代码可以发现改代码通过获取分页的总页数来动态的创建<a>标签。我们来看一下最后的效果: