利用Bootstrap Paginator插件和KnockoutJS完成分页功能
在最近一个项目中,需要结合一堆条件查询并对查询的结果数据完成一个简单分页功能,可是做着做着,自己的思路越来越模糊,做到心态崩溃!!! 哈哈,特此花点时间重新总结,并从最简单的分页,然后向多条件查询分页慢慢过渡,或许有人觉得这个很简单(可以绕道啦,哈哈),却是对基础知识的一次学习过程。
Demo地址:https://gitee.com/530521314/Partner.TreasureChest/tree/master/Pagination/
本文地址:https://www.cnblogs.com/CKExp/p/9218904.html
一、环境介绍
分页功能很多已有的很完美的插件或是第三方应用包都能够完美实现,我在此利用了一些前端插件来完成分页功能。
前端的Bootstrap Paginator插件完成前端分页数字之类的切换展示;
利用knockout.js插件完成分页数据的绑定;
在后端,利用asp.net core mvc 完成分页信息的接收和处理工作。
二、简单分页
完成对已有数据的分页功能,不带条件查询。
首先,一上来便是完成数据绑定工作:
bookList: ko.mapping.fromJS(@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model))),//展示数据
pageEntity: ko.mapping.fromJS(@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(new PageRequestViewModel()))),//分页信息
页面刚展示的时候得有分页数据吧,可以在当页面展示的时候,数据也带过来了,也可以页面展示后,再通过ajax去后台调用,我选择后者。
在页面启动时,调用该函数完成初始化页面数据。
getBookData: function () {
var pageEntity = ko.mapping.toJS(viewModel.pageEntity);
$.ajax({
url: '@Url.Action("SampleGetData")',
type: 'POST',
dataType: 'json',
data: pageEntity,
success: function (result) {
ko.mapping.fromJS(result.data, viewModel.bookList);
options.totalPages = result.totalCount > 0 ? result.totalCount % options.numberOfPages == 0 ?
result.totalCount / options.numberOfPages : (result.totalCount / options.numberOfPages) + 1 : 1;
$('#pagination').bootstrapPaginator(options);
}
});
}
分页信息(当前页面,页面展示数据条数)带过去,后台根据分页信息完成数据查询,并获得总的记录条数用于前端页面计算总页数。
[HttpPost]
public IActionResult SampleGetData(PageRequestViewModel pageEntity)
{
var bookList = PageDataSeed.GetPageDataList()
.Skip((pageEntity.PageIndex - ) * pageEntity.PageSize)
.Take(pageEntity.PageSize); var pageResultViewModel = new PageResultViewModel<Book>()
{
PageIndex = pageEntity.PageIndex,
PageSize = pageEntity.PageSize,
TotalCount = PageDataSeed.GetPageDataList().Count(),
Data = bookList
}; return Json(pageResultViewModel);
}
根据分页信息查询也就搞定了,当点击底部的页面码的时候得改变当前分页信息,然后要切换当前分页信息所对应的数据出来,在Bootstrap paginator插件中,点击页面码有一个函数onPageClicked,点击具体的某一页后,根据参数page获得页面,改变当前展示的页面码数字,并对分页信息修改,然后再次调用ajax获得新数据。
onPageClicked: function (event, originalEvent, type, page) {
options.currentPage = page;
viewModel.pageEntity.PageIndex = page;
viewModel.getBookData();
},
至此,简单分页功能便搞定了,在此实现中,偏重于前端实现分页逻辑,后台只是取得相应的数据。

三、单条件查询分页
复制一份简单分页后,改造下加入一个根据书名条件项,查询后完成分页功能。
首先加入书名绑定,在此用了两个书名,第二个是有目的性的留着,也只是我的理解,条件查询后,如果底部展示有多页,那么我在点击每一页的时候,我的查询条件不能动吧,基于此考虑的。
bookName: ko.observable(),
bookNameBackup: ko.observable(),
数据查询部分改动不大,主要是把查询条件加入进来,因此只改动data参数即可。
getBookData: function () {
var pageEntity = ko.mapping.toJS(viewModel.pageEntity);
$.ajax({
url: '@Url.Action("SingleQueryGetData")',
type: 'POST',
dataType: 'json',
data: {"pageEntity":pageEntity, "bookName":viewModel.bookName()},
success: function (result) {
ko.mapping.fromJS(result.data, viewModel.bookList);
options.totalPages = result.totalCount > 0 ? result.totalCount % options.numberOfPages == 0 ?
result.totalCount / options.numberOfPages : (result.totalCount / options.numberOfPages) + 1 : 1;
$('#pagination').bootstrapPaginator(options);
}
});
},
前端Html部分加入单条件项,以书名为例,查询按钮绑定点击后的触发函数
<div class="form-group">
<label for="bookName" class="col-sm-2 control-label">书名</label>
<div class="col-sm-2">
<input type="text" class="form-control" id="bookName" data-bind="value:bookName">
</div>
<button class="btn btn-primary col-sm-1" data-bind="click:queryBookList">查询</button>
</div>
点击查询后执行函数,将当前页面重置为1,查询数据,并记录该次查询的查询条件。
//查询
queryBookList: function () {
options.currentPage = 1;
viewModel.pageEntity.PageIndex = options.currentPage;
viewModel.getBookData();
viewModel.bookNameBackup(viewModel.bookName());//记录查询条件,分页点击时需要用到
}
查询完毕,然后假设底部还存在很多页面码可以选择,当我们点击页面码的时候,因为查询条件仍然存在,我们点击后仍然会完成分页功能,但是!!!
当把查询条件清空,比如在此demo中,把书名置空,此时不点查询按钮,而是直接点击页面码,那情况会如何呢,查询条件已经没了;
或是说查询条件为空时,输入查询条件,不点查询按钮,直接点击页面码;
这都是不合理的情形,点击页面码的时候肯定得保证原查询条件的存在,至少我是这么想的,或许您有更好的建议,请告诉我,十分感谢。这也就是我在之前设置了一个监控对象bookNameBackup的原因,备份查询条件,防止点击页码切换时查询条件变更的情形。
前端已经改好了,然后进入后端来改一下,先对条件判空处理,然后执行相应的逻辑。
[HttpPost]
public IActionResult SingleQueryGetData(PageRequestViewModel pageEntity, string bookName)
{
IEnumerable<Book> bookList = PageDataSeed.GetPageDataList();
PageResultViewModel<Book> pageResultViewModel = null; if (!string.IsNullOrEmpty(bookName))
bookList = bookList.Where(b => b.BookName.Contains(bookName)); var books = bookList.Skip((pageEntity.PageIndex - ) * pageEntity.PageSize)
.Take(pageEntity.PageSize); pageResultViewModel = new PageResultViewModel<Book>()
{
PageIndex = pageEntity.PageIndex,
PageSize = pageEntity.PageSize,
TotalCount = bookList.Count(),
Data = books
}; return Json(pageResultViewModel);
}
单条件查询分页功能也就搞定了,查询和点击页面码所执行的逻辑是不一样的,虽然都调用到了最终的数据查询方法,但是对于条件的处理是不一样的。

四、多条件查询分页
对单条件查询分页下多加入几个条件,进入到多条件查询,变化其实不大,只是为了方便管理如此多的查询条件,改成了以对象形式管理
首先绑定查询对象信息,该对象中包括了三个查询条件,书名,作者,出版社,仍然设置一个备份对象,原因和单条件查询下是一样的。
queryItemEntity: ko.mapping.fromJS(@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(new QueryItemViewModel()))),//查询条件信息
queryItemEntityBackup: ko.mapping.fromJS(@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(new QueryItemViewModel()))),//查询条件信息备份
页面的查询条件多了,通过queryItemEntity为前缀展示,也方便维护
<div id="queryItem" class="form-horizontal">
<div class="form-group">
<label for="bookName" class="col-sm-2 control-label">书名</label>
<div class="col-sm-2">
<input type="text" class="form-control" id="bookName" data-bind="value:queryItemEntity.BookName">
</div>
<label for="author" class="col-sm-2 control-label">作者</label>
<div class="col-sm-2">
<input type="text" class="form-control" id="author" data-bind="value:queryItemEntity.Author">
</div>
<label for="press" class="col-sm-2 control-label">出版社</label>
<div class="col-sm-2">
<input type="text" class="form-control" id="press" data-bind="value:queryItemEntity.Press">
</div>
</div>
<button class="btn btn-primary" data-bind="click:queryBookList">查询</button>
</div>
查询条件改动,也使得数据查询部分的条件改变了,将查询条件整体封装,而不是零散的传递,改动之处加入了第三行将ko上的查询条件信息转换为JS对象和改变了参数data的值。
getBookData: function () {
var pageEntity = ko.mapping.toJS(viewModel.pageEntity);
var queryItemEntity = ko.mapping.toJS(viewModel.queryItemEntity);
$.ajax({
url: '@Url.Action("MultipleQueryGetData")',
type: 'POST',
dataType: 'json',
data: { "pageEntity": pageEntity, "queryItemEntity": queryItemEntity},
success: function (result) {
ko.mapping.fromJS(result.data, viewModel.bookList);
options.totalPages = result.totalCount > 0 ? result.totalCount % options.numberOfPages == 0 ?
result.totalCount / options.numberOfPages : (result.totalCount / options.numberOfPages) + 1 : 1;
$('#pagination').bootstrapPaginator(options);
}
});
},
点击按钮查询处的逻辑还是没有改变,仍然是查询记录并将查询条件备份,用于分页控件中页面码的点击函数。
//查询
queryBookList: function () {
options.currentPage = 1;
viewModel.pageEntity.PageIndex = options.currentPage;
viewModel.getBookData();
ko.mapping.fromJS(viewModel.queryItemEntity, viewModel.queryItemEntityBackup);//记录查询条件,分页点击时需要用到
}
对于前端来讲改动并不是很大,无非是将查询条件封装一下,同样后端的改动只是多个查询条件的过滤,依次比对三个查询条件是否为空,并挨个去完成查询的过滤。
[HttpPost]
public IActionResult MultipleQueryGetData(PageRequestViewModel pageEntity, QueryItemViewModel queryItemEntity)
{
var bookList = PageDataSeed.GetPageDataList(); #region 条件过滤
if (!string.IsNullOrEmpty(queryItemEntity.BookName))
bookList = bookList.Where(b => b.BookName.Contains(queryItemEntity.BookName)).ToList();
if (!string.IsNullOrEmpty(queryItemEntity.Author))
bookList = bookList.Where(b => b.Author.Contains(queryItemEntity.Author)).ToList();
if (!string.IsNullOrEmpty(queryItemEntity.Press))
bookList = bookList.Where(b => b.Press.Contains(queryItemEntity.Press)).ToList();
#endregion var books = bookList.Skip((pageEntity.PageIndex - ) * pageEntity.PageSize).Take(pageEntity.PageSize); var pageResultViewModel = new PageResultViewModel<Book>()
{
PageIndex = pageEntity.PageIndex,
PageSize = pageEntity.PageSize,
TotalCount = bookList.Count(),
Data = books
}; return Json(pageResultViewModel);
}
多条件查询分页的效果展示

至此,查询功能算是简单完成了,或许还有漏洞地方,没有发现,特别是逻辑漏洞,防不胜防,望多指教,感谢。
设计一个小Demo一方面是对分页功能进行一下总结,以防自己若干天或是若干年后还需要,可以回来看看,一方面也是如果有需要的朋友可以加快编码和设计的过程。
码云上存放Demo的地址:https://gitee.com/530521314/Partner.TreasureChest/tree/master/Pagination/
2018-6-24,望技术有成后能回来看见自己的脚步
利用Bootstrap Paginator插件和KnockoutJS完成分页功能的更多相关文章
- C#设计模式总结 C#设计模式(22)——访问者模式(Vistor Pattern) C#设计模式总结 .NET Core launch.json 简介 利用Bootstrap Paginator插件和knockout.js完成分页功能 图片在线裁剪和图片上传总结 循序渐进学.Net Core Web Api开发系列【2】:利用Swagger调试WebApi
C#设计模式总结 一. 设计原则 使用设计模式的根本原因是适应变化,提高代码复用率,使软件更具有可维护性和可扩展性.并且,在进行设计的时候,也需要遵循以下几个原则:单一职责原则.开放封闭原则.里氏代替 ...
- 利用BootStrap Table插件实现自己的弹出框分页。
参考链接1: 官网:http://bootstrap-table.wenzhixin.net.cn/zh-cn/home/ 开始使用:http://bootstrap-table. ...
- 传统方式和插件方式 分别实现 分页 功能 pageHelper 插件
实现分页 这里提供两种方式 一种是传统的分页方式 一种是基于pageHelper插件 实现的分类 推荐使用后者 前者是一般开发的方式 思路 先手动创建一个 pageUtil 工具 ...
- Bootstrap Paginator分页插件+ajax 实现动态无刷新分页
之前做分页想过做淘宝的那个,但是因为是后台要求不高,就Bootstrap Paginator插件感觉还蛮容易上手,所以就选了它. Bootstrap Paginator分页插件下载地址: Downlo ...
- Django 实现分页功能(django 2.2.7 python 3.7.5 )
Django 自带名为 Paginator 的分页工具, 方便我们实现分页功能.本文就讲解如何使用 Paginator 实现分页功能. 一. Paginator Paginator 类的作用是将我们需 ...
- bootstrap分页插件--Bootstrap Paginator的使用&AJAX版备份(可单独使用)
html部分: <ul class="pagination"></ul> <!--bootstrap3版本用ul包裹--> <div cl ...
- Bootstrap Paginator 分页插件参数介绍及使用
Bootstrap Paginator是一款基于Bootstrap的js分页插件,功能很丰富,个人觉得这款插件已经无可挑剔了.它提供了一系列的参数用来支持用户的定制,提供了公共的方法可随时获得插件状态 ...
- Bootstrap Paginator分页插件的使用
今天,我为大家带来的一款做得非常优秀的分页插件BootStrap Paginator,他是一款js插件,由于本人也是才刚刚搞出来的,所以暂时对它也不是特别了解,只能大楖告诉大家怎么使用.我这里使用的是 ...
- Bootstrap Paginator分页插件
Bootstrap Paginator分页插件使用示例 最近做的asp.netMVC项目中需要对数据列表进行分类,这个本来就是基于bootstrap开发的后台,因此也就想着bootstrap是否有分页 ...
随机推荐
- Math.pow();Math.sqrt();
//Math.pow(a,b)功能是a的b次方 (int)Math.sqrt(n):先对n开方,然后转成int类型//例如,(int)Math.sqrt(2)=(int)1.414=1 Math.ab ...
- Oracle的nvl
在Oracle中nvl(字段名,value)函数用于对没有值的字段做处理在MySql中ifnull(字段名,value)是一样的功能
- BZOJ_2661_[BeiJing wc2012]连连看_费用流
BZOJ_2661_[BeiJing wc2012]连连看_费用流 Description 凡是考智商的题里面总会有这么一种消除游戏.不过现在面对的这关连连看可不是QQ游戏里那种考眼力的游戏.我们的规 ...
- BZOJ4554: [Tjoi2016&Heoi2016]游戏 luoguP2825 loj2057
题面描述:尽可能多的放置符合要求的炸弹. 分析: 在i,j处放置炸弹,则在第i行,上一个硬石头之后,下一个硬石头之前,第j列,上一个硬石头之后,下一个硬石头之前,不能再次放置炸弹. 首先,这个题,一看 ...
- 显著性检测(saliency detection)评价指标之KL散度距离Matlab代码实现
步骤1:先定义KLdiv函数: function score = KLdiv(saliencyMap, fixationMap) % saliencyMap is the saliency map % ...
- PCB泪滴设计
操作:选择[Tools]-->[Teardrops],快捷键T+E.打开[Teardrop Options]对话框进行设置.如下图所示: 对话框面板介绍 [General] 1.该区域的[Pad ...
- Treap与fhq_Treap学习笔记
1.普通Treap 通过左右旋来维护堆的性质 左右旋是不改变中序遍历的 #include<algorithm> #include<iostream> #include<c ...
- 解决 'boost/iterator/iterator_adaptor.hpp' file not found’ 及控制台":CFBundleIdentifier", Does Not Exist
"react-native": "0.46.1" 这个问题产生原因: * /Users/Vanessa/.rncache 中 boost_1_63_0.tar. ...
- Mark一下~
今天在cnblogs开通了博客,mark一下~ 上半年的Rebase阶段已经完成,希望下半年的Promotion阶段能收获满满,也希望自己能写出高质量的博客.
- Eclipse Debug调试遇到的问题
在使用Debug模式前,一定要先打好断点.快捷调试方法: 在使用过程中,可以只保留Console,Variables,Debug窗口,把其他无用的窗口最小化掉,或者删掉即可.如果要恢复删掉的试图, ...