Demo地址:https://gitee.com/530521314/Partner.TreasureChest/tree/master/Pagination/html
本文地址:http://www.javashuo.com/article/p-ogyapptc-ca.html前端
分页功能不少已有的很完美的插件或是第三方应用包都可以完美实现,我在此利用了一些前端插件来完成分页功能。java
前端的Bootstrap Paginator插件完成前端分页数字之类的切换展现;jquery
利用knockout.js插件完成分页数据的绑定;git
在后端,利用asp.net core mvc 完成分页信息的接收和处理工做。ajax
完成对已有数据的分页功能,不带条件查询。json
首先,一上来即是完成数据绑定工做:bootstrap
1 bookList: ko.mapping.fromJS(@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model))),//展现数据 2 pageEntity: ko.mapping.fromJS(@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(new PageRequestViewModel()))),//分页信息
页面刚展现的时候得有分页数据吧,能够在当页面展现的时候,数据也带过来了,也能够页面展现后,再经过ajax去后台调用,我选择后者。后端
在页面启动时,调用该函数完成初始化页面数据。mvc
1 getBookData: function () { 2 var pageEntity = ko.mapping.toJS(viewModel.pageEntity); 3 $.ajax({ 4 url: '@Url.Action("SampleGetData")', 5 type: 'POST', 6 dataType: 'json', 7 data: pageEntity, 8 success: function (result) { 9 ko.mapping.fromJS(result.data, viewModel.bookList); 10 options.totalPages = result.totalCount > 0 ? result.totalCount % options.numberOfPages == 0 ? 11 result.totalCount / options.numberOfPages : (result.totalCount / options.numberOfPages) + 1 : 1; 12 $('#pagination').bootstrapPaginator(options); 13 } 14 }); 15 }
分页信息(当前页面,页面展现数据条数)带过去,后台根据分页信息完成数据查询,并得到总的记录条数用于前端页面计算总页数。
1 [HttpPost] 2 public IActionResult SampleGetData(PageRequestViewModel pageEntity) 3 { 4 var bookList = PageDataSeed.GetPageDataList() 5 .Skip((pageEntity.PageIndex - 1) * pageEntity.PageSize) 6 .Take(pageEntity.PageSize); 7 8 var pageResultViewModel = new PageResultViewModel<Book>() 9 { 10 PageIndex = pageEntity.PageIndex, 11 PageSize = pageEntity.PageSize, 12 TotalCount = PageDataSeed.GetPageDataList().Count(), 13 Data = bookList 14 }; 15 16 return Json(pageResultViewModel); 17 }
根据分页信息查询也就搞定了,当点击底部的页面码的时候得改变当前分页信息,而后要切换当前分页信息所对应的数据出来,在Bootstrap paginator插件中,点击页面码有一个函数onPageClicked,点击具体的某一页后,根据参数page得到页面,改变当前展现的页面码数字,并对分页信息修改,而后再次调用ajax得到新数据。
1 onPageClicked: function (event, originalEvent, type, page) { 2 options.currentPage = page; 3 viewModel.pageEntity.PageIndex = page; 4 viewModel.getBookData(); 5 },
至此,简单分页功能便搞定了,在此实现中,偏重于前端实现分页逻辑,后台只是取得相应的数据。
复制一份简单分页后,改造下加入一个根据书名条件项,查询后完成分页功能。
首先加入书名绑定,在此用了两个书名,第二个是有目的性的留着,也只是个人理解,条件查询后,若是底部展现有多页,那么我在点击每一页的时候,个人查询条件不能动吧,基于此考虑的。
1 bookName: ko.observable(), 2 bookNameBackup: ko.observable(),
数据查询部分改动不大,主要是把查询条件加入进来,所以只改动data参数便可。
1 getBookData: function () { 2 var pageEntity = ko.mapping.toJS(viewModel.pageEntity); 3 $.ajax({ 4 url: '@Url.Action("SingleQueryGetData")', 5 type: 'POST', 6 dataType: 'json', 7 data: {"pageEntity":pageEntity, "bookName":viewModel.bookName()}, 8 success: function (result) { 9 ko.mapping.fromJS(result.data, viewModel.bookList); 10 options.totalPages = result.totalCount > 0 ? result.totalCount % options.numberOfPages == 0 ? 11 result.totalCount / options.numberOfPages : (result.totalCount / options.numberOfPages) + 1 : 1; 12 $('#pagination').bootstrapPaginator(options); 13 } 14 }); 15 },
前端Html部分加入单条件项,以书名为例,查询按钮绑定点击后的触发函数
1 <div class="form-group"> 2 <label for="bookName" class="col-sm-2 control-label">书名</label> 3 <div class="col-sm-2"> 4 <input type="text" class="form-control" id="bookName" data-bind="value:bookName"> 5 </div> 6 <button class="btn btn-primary col-sm-1" data-bind="click:queryBookList">查询</button> 7 </div>
点击查询后执行函数,将当前页面重置为1,查询数据,并记录该次查询的查询条件。
1 //查询 2 queryBookList: function () { 3 options.currentPage = 1; 4 viewModel.pageEntity.PageIndex = options.currentPage; 5 viewModel.getBookData(); 6 viewModel.bookNameBackup(viewModel.bookName());//记录查询条件,分页点击时须要用到 7 }
查询完毕,而后假设底部还存在不少页面码能够选择,当咱们点击页面码的时候,由于查询条件仍然存在,咱们点击后仍然会完成分页功能,可是!!!
当把查询条件清空,好比在此demo中,把书名置空,此时不点查询按钮,而是直接点击页面码,那状况会如何呢,查询条件已经没了;
或是说查询条件为空时,输入查询条件,不点查询按钮,直接点击页面码;
这都是不合理的情形,点击页面码的时候确定得保证原查询条件的存在,至少我是这么想的,或许您有更好的建议,请告诉我,十分感谢。这也就是我在以前设置了一个监控对象bookNameBackup的缘由,备份查询条件,防止点击页码切换时查询条件变动的情形。
前端已经改好了,而后进入后端来改一下,先对条件判空处理,而后执行相应的逻辑。
1 [HttpPost] 2 public IActionResult SingleQueryGetData(PageRequestViewModel pageEntity, string bookName) 3 { 4 IEnumerable<Book> bookList = PageDataSeed.GetPageDataList(); 5 PageResultViewModel<Book> pageResultViewModel = null; 6 7 if (!string.IsNullOrEmpty(bookName)) 8 bookList = bookList.Where(b => b.BookName.Contains(bookName)); 9 10 var books = bookList.Skip((pageEntity.PageIndex - 1) * pageEntity.PageSize) 11 .Take(pageEntity.PageSize); 12 13 pageResultViewModel = new PageResultViewModel<Book>() 14 { 15 PageIndex = pageEntity.PageIndex, 16 PageSize = pageEntity.PageSize, 17 TotalCount = bookList.Count(), 18 Data = books 19 }; 20 21 return Json(pageResultViewModel); 22 }
单条件查询分页功能也就搞定了,查询和点击页面码所执行的逻辑是不同的,虽然都调用到了最终的数据查询方法,可是对于条件的处理是不同的。
对单条件查询分页下多加入几个条件,进入到多条件查询,变化其实不大,只是为了方便管理如此多的查询条件,改为了以对象形式管理
首先绑定查询对象信息,该对象中包括了三个查询条件,书名,做者,出版社,仍然设置一个备份对象,缘由和单条件查询下是同样的。
1 queryItemEntity: ko.mapping.fromJS(@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(new QueryItemViewModel()))),//查询条件信息 2 queryItemEntityBackup: ko.mapping.fromJS(@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(new QueryItemViewModel()))),//查询条件信息备份
页面的查询条件多了,经过queryItemEntity为前缀展现,也方便维护
1 <div id="queryItem" class="form-horizontal"> 2 <div class="form-group"> 3 <label for="bookName" class="col-sm-2 control-label">书名</label> 4 <div class="col-sm-2"> 5 <input type="text" class="form-control" id="bookName" data-bind="value:queryItemEntity.BookName"> 6 </div> 7 <label for="author" class="col-sm-2 control-label">做者</label> 8 <div class="col-sm-2"> 9 <input type="text" class="form-control" id="author" data-bind="value:queryItemEntity.Author"> 10 </div> 11 <label for="press" class="col-sm-2 control-label">出版社</label> 12 <div class="col-sm-2"> 13 <input type="text" class="form-control" id="press" data-bind="value:queryItemEntity.Press"> 14 </div> 15 </div> 16 <button class="btn btn-primary" data-bind="click:queryBookList">查询</button> 17 </div>
查询条件改动,也使得数据查询部分的条件改变了,将查询条件总体封装,而不是零散的传递,改动之处加入了第三行将ko上的查询条件信息转换为JS对象和改变了参数data的值。
1 getBookData: function () { 2 var pageEntity = ko.mapping.toJS(viewModel.pageEntity); 3 var queryItemEntity = ko.mapping.toJS(viewModel.queryItemEntity); 4 5 $.ajax({ 6 url: '@Url.Action("MultipleQueryGetData")', 7 type: 'POST', 8 dataType: 'json', 9 data: { "pageEntity": pageEntity, "queryItemEntity": queryItemEntity}, 10 success: function (result) { 11 ko.mapping.fromJS(result.data, viewModel.bookList); 12 options.totalPages = result.totalCount > 0 ? result.totalCount % options.numberOfPages == 0 ? 13 result.totalCount / options.numberOfPages : (result.totalCount / options.numberOfPages) + 1 : 1; 14 $('#pagination').bootstrapPaginator(options); 15 } 16 }); 17 },
点击按钮查询处的逻辑仍是没有改变,仍然是查询记录并将查询条件备份,用于分页控件中页面码的点击函数。
1 //查询 2 queryBookList: function () { 3 options.currentPage = 1; 4 viewModel.pageEntity.PageIndex = options.currentPage; 5 viewModel.getBookData(); 6 ko.mapping.fromJS(viewModel.queryItemEntity, viewModel.queryItemEntityBackup);//记录查询条件,分页点击时须要用到 7 }
对于前端来说改动并非很大,无非是将查询条件封装一下,一样后端的改动只是多个查询条件的过滤,依次比对三个查询条件是否为空,并挨个去完成查询的过滤。
1 [HttpPost] 2 public IActionResult MultipleQueryGetData(PageRequestViewModel pageEntity, QueryItemViewModel queryItemEntity) 3 { 4 var bookList = PageDataSeed.GetPageDataList(); 5 6 #region 条件过滤 7 if (!string.IsNullOrEmpty(queryItemEntity.BookName)) 8 bookList = bookList.Where(b => b.BookName.Contains(queryItemEntity.BookName)).ToList(); 9 if (!string.IsNullOrEmpty(queryItemEntity.Author)) 10 bookList = bookList.Where(b => b.Author.Contains(queryItemEntity.Author)).ToList(); 11 if (!string.IsNullOrEmpty(queryItemEntity.Press)) 12 bookList = bookList.Where(b => b.Press.Contains(queryItemEntity.Press)).ToList(); 13 #endregion 14 15 var books = bookList.Skip((pageEntity.PageIndex - 1) * pageEntity.PageSize).Take(pageEntity.PageSize); 16 17 var pageResultViewModel = new PageResultViewModel<Book>() 18 { 19 PageIndex = pageEntity.PageIndex, 20 PageSize = pageEntity.PageSize, 21 TotalCount = bookList.Count(), 22 Data = books 23 }; 24 25 return Json(pageResultViewModel); 26 }
多条件查询分页的效果展现
至此,查询功能算是简单完成了,或许还有漏洞地方,没有发现,特别是逻辑漏洞,防不胜防,望多指教,感谢。
设计一个小Demo一方面是对分页功能进行一下总结,以防本身若干天或是若干年后还须要,能够回来看看,一方面也是若是有须要的朋友能够加快编码和设计的过程。
码云上存放Demo的地址:https://gitee.com/530521314/Partner.TreasureChest/tree/master/Pagination/
2018-6-24,望技术有成后能回来看见本身的脚步