利用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是否有分页 ...
随机推荐
- Nodejs.调用Linux命令
当需要Node.js在后台帮忙运行Linux命令脚本时, 可以用上以下方法 上代码 var spawn = require('child_process').spawn; free = spawn(' ...
- 【NOIP模拟赛】随
题目链接: 172.18.111.252:800/problem.php?cid=1001&pid=0 题解: 膜达神……(NOIP考这个就等爆零吧……) 显然我们得到一个结论:$ans=\s ...
- [Usaco2015 Jan]Grass Cownoisseur 图论 tarjan spfa
先缩点,对于缩点后的DAG,正反跑spfa,枚举每条边进行翻转即可 #include<cstdio> #include<cstring> #include<iostrea ...
- Windbg分析高内存占用问题
1. 问题简介 最近产品发布大版本补丁更新,一商超客户升级后,反馈系统经常奔溃,导致超市的收银系统无法正常收银,现场排队付款的顾客更是抱怨声声.为了缓解现场的情况, 客户都是手动回收IIS应用程序池才 ...
- Java Native Interface调用C++代码
概述 Java Native Interface译为Java原生接口,简称JNI.Java并不是完美的,它的不足体现在运行速度要比传统的C++慢上许多,并且无法直接访问到操作系统底层,为此Java提供 ...
- C#-Xamarin的Android项目开发(二)——控件应用
相信我,这不是一篇吐槽文章.... 基础控件 Android的控件和控件样式非常特别,它是一种内联特别高的设计模式,换句话说,它是非常烂的设计.... 但在这种特别的关系里还是有一定的规律的,下面我们 ...
- Logistic回归二分类Winner or Losser----台大李宏毅机器学习作业二(HW2)
一.作业说明 给定训练集spam_train.csv,要求根据每个ID各种属性值来判断该ID对应角色是Winner还是Losser(0.1分类). 训练集介绍: (1)CSV文件,大小为4000行X5 ...
- Bumblebee之负载、限流和故障处理实践
Bumblebee作为标准HTTP 1.1应用协议的网关,它能作为任何基于HTTP 1.1构建Webapi服务的前置网关.以下通过示例讲述如何用Bumblebee来制作一个asp.net core w ...
- Android版数据结构与算法(八):二叉排序树
本文目录 前两篇文章我们学习了一些树的基本概念以及常用操作,本篇我们了解一下二叉树的一种特殊形式:二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree) ...
- Fundebug支付宝小程序BUG监控插件更新至0.2.0,新增test()方法,报错增加Page数据
摘要: 0.2.0新增fundebug.test()方法,同时报错增加了Page数据. Fundebug提供专业支付宝小程序BUG监控服务,可以第一时间为您捕获生存环境中小程序的异常.错误或者BUG, ...