ASP.NET MVC分页 Ajax+JsRender
前段时间整mvc的分页,倒是很顺利,参考了以下几篇博客,启发很大。
http://www.cnblogs.com/tangmingjun/archive/2012/05/30/2526301.html
http://www.cnblogs.com/tangmingjun/archive/2012/05/31/2528732.html
顺便扩展了需求,在分页的基础上,继续做关键字查询。
用PagedList生成的页码链接虽然样式很漂亮,但是要做到无刷新的分页,PagedList自动生成的代码是不够用的,可以配合jsRender和Ajax做上面的效果,同时手动构建PagedList生成的页码标签,根据自己的需要设置href和onclick事件。
直接上代码
前台:
@{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>商品信息</h2> <p> @Html.ActionLink("新建", "Create") | @Html.Editor("txtSearch") <input type="button" value="查找" id="btnSearch" /> <img id="imgWaiting" src="~/Images/loading.gif" style="display:none; width:30px; height:30px;" /> </p> <table class="table"> <thead> <tr> <th>商品名称</th> <th>商品描述</th> <th>原价</th> <th>特价(现价)</th> <th>销量</th> <th>修改日期</th> <th>商品链接</th> <th>状态</th> <th>图片</th> <th></th> </tr> </thead> <tbody id="tblContent"></tbody> </table> <div id="divPage"></div> <script type="text/x-jsrender" id="contentTemplate"> <tr> <td>{{:GoodName}}</td> <td>{{:Description}}</td> <td>{{:OriginalPrice}}</td> <td>{{:SpecialPrice}}</td> <td>{{:Sales}}</td> <td>{{:ActiveTime}}</td> <td>{{:Url}}</td> <td>{{:Status}}</td> <td>{{:PicPath}}@*<img id="PicPath" src="{{:PicPath}}" class="thumbnailPdt" />*@</td> <td> <a href="/Admin/Goods/Edit/{{:GoodID}}">Edit</a> | <a href="/Admin/Goods/Delete/{{:GoodID}}">Delete</a> </td> </tr> </script> @section Scripts{ <script src="~/Scripts/jsrender.min.js" type="text/javascript"></script> <script> var key = ""; function doSearch(page) { key = $("#txtSearch").val(); $.post( "/Admin/Goods/SearchProduct", { keyword: key, pageNo: page }, function (data, status) { //数据写到前台 $("#tblContent").html($("#contentTemplate").render(data.contents)); $("#divPage").html(data["pageList"]); }, "json" ); }; //绑定点击查询事件 $("#btnSearch").click(function () { doSearch(1); }); //输入框回车开始查询 $("#txtFilter").bind("keypress", function () { if (event.keyCode == 13) { $("#btnSearch").click(); return false; } }); //加载初始化数据 $(function () { doSearch(1); }); </script> }
后台Controller:
public ActionResult Index() { return View(); } public JsonResult SearchProduct(string keyword, int? pageNo) { int pageIndex = pageNo ?? 1; int totalCount; var goods = GetSearchData(keyword, ref pageIndex, _PageSize, out totalCount); int totalPage = totalCount / _PageSize + (totalCount % _PageSize == 0 ? 0 : 1); var pagerHtml = ExHtml.CreatePagesHtml(totalPage, pageIndex); return Json(new { contents = goods, pageList = pagerHtml }, JsonRequestBehavior.DenyGet); } List<Good> GetSearchData(string keyword, ref int pageIndex, int pageSize, out int totalCount) { var linq = from p in db.Goods select p; if (!string.IsNullOrWhiteSpace(keyword)) { linq = linq.Where(t => t.GoodID.ToString() == keyword || t.GoodName.Contains(keyword) || t.Description.Contains(keyword) ); } totalCount = linq.Count(); //修正pageIndex var maxPage = totalCount / pageSize + (totalCount % pageSize == 0 ? 0 : 1); if (pageIndex < 1) pageIndex = 1; if (pageIndex > maxPage) pageIndex = maxPage; linq = linq.OrderByDescending(x => x.GoodID) .Skip((pageIndex - 1) * pageSize) .Take(pageSize); return linq.ToList(); }
扩展函数:
public static string CreatePagesHtml(int totalPageNo, int currPageNo, string jsClickName = "doSearch") { if (currPageNo > totalPageNo || currPageNo < 1 || totalPageNo == 1) return ""; string res = ""; if (currPageNo > 3) res += LiForFirst(jsClickName);//有跳转到第一页 //if (currPageNo > 2) res += LiForPrev(currPageNo - 1, jsClickName);//跳转到前一页 if (currPageNo > 4) res += LiForOthers();//无跳转,显示中间有页面 if (currPageNo > 2) res += LiForPage(currPageNo - 2, jsClickName);//前两页 if (currPageNo > 1) res += LiForPage(currPageNo - 1, jsClickName);//前一页 res += LiForCurr(currPageNo);//当前页 if (currPageNo < totalPageNo) res += LiForPage(currPageNo + 1, jsClickName);//下一页 if (currPageNo < totalPageNo - 1) res += LiForPage(currPageNo + 2, jsClickName);//下两页 if (currPageNo < totalPageNo - 3) res += LiForOthers();//无跳转,显示中间有页面 //if (currPageNo < totalPageNo - 1) res += LiForNext(currPageNo + 1, jsClickName);//跳转到后一页 if (currPageNo < totalPageNo - 2) res += LiForLast(totalPageNo, jsClickName);//跳转到最后页 return string.Format(@" <div class=""pagination-container""> <ul class=""pagination""> {0} </ul> </div>" , res); } static string GetPageItem(int pageNo, string text, string jsClickName, string classStr = null, string rel = null) { return string.Format(@"<li{0}><a href=""#""{1}{2}>{3}</a></li>" , string.IsNullOrWhiteSpace(classStr) ? "" : " class=\"" + classStr + "\"" , string.IsNullOrWhiteSpace(rel) ? "" : " rel=\"" + rel + "\"" , string.IsNullOrWhiteSpace(jsClickName) ? "" : string.Format(" onclick=\"{0}({1});\"", jsClickName, pageNo) , text ); } static string LiForFirst(string jsClickName) { return GetPageItem(1, "1"/*"««"*/, jsClickName, classStr: "PagedList-skipToFirst"); } static string LiForPrev(int pageNo, string jsClickName) { return GetPageItem(pageNo, "«", jsClickName, classStr: "PagedList-skipToPrevious", rel: "prev"); } static string LiForNext(int pageNo, string jsClickName) { return GetPageItem(pageNo, "»", jsClickName, classStr: "PagedList-skipToNext", rel: "next"); } static string LiForLast(int totalPageNo, string jsClickName) { return GetPageItem(totalPageNo, totalPageNo.ToString()/*"»»"*/, jsClickName, classStr: "PagedList-skipToLast"); } static string LiForPage(int pageNo, string jsClickName) { return GetPageItem(pageNo, pageNo.ToString(), jsClickName); } static string LiForCurr(int pageNo) { return GetPageItem(pageNo, pageNo.ToString(), null, classStr: "active"); } static string LiForOthers() { return GetPageItem(0, "…", null, classStr: "disabled PagedList-ellipses"); }
前台的关键代码是js函数doSearch,通过post发送请求,请求成功后处理返回的json数据,并重新加载页面部分元素。json数据包有两个属性,一个contents,里面是类型为List<T>的数据,通过jsrender的调用,生成前台表格的tbody中的代码;另一个pageList是后台组装好的,显示page按钮的string。
后台Controller代码中,主要是第二个函数SearchProduct,它可以作为一个controller下面的action调用,在里面执行查询数据,以及组装pageHtml的操作,并打包这些数据成json数据,返回给前台。
扩展函数代码则主要是组装page的string结果。这部分参考PagedList生成的页码标签的代码,样式在bootstrap里面都有。
环境:VS2013 + MVC5.0 + Bootstrap 3.0
JsRender下载地址
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。