在最近一个项目中,需要结合一堆条件查询并对查询的结果数据完成一个简单分页功能,可是做着做着,自己的思路越来越模糊,做到心态崩溃!!! 哈哈,特此花点时间重新总结,并从最简单的分页,然后向多条件查询分页慢慢过渡,或许有人觉得这个很简单(可以绕道啦,哈哈),却是对基础知识的一次学习过程。

  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完成分页功能的更多相关文章

  1. C#设计模式总结 C#设计模式(22)——访问者模式(Vistor Pattern) C#设计模式总结 .NET Core launch.json 简介 利用Bootstrap Paginator插件和knockout.js完成分页功能 图片在线裁剪和图片上传总结 循序渐进学.Net Core Web Api开发系列【2】:利用Swagger调试WebApi

    C#设计模式总结 一. 设计原则 使用设计模式的根本原因是适应变化,提高代码复用率,使软件更具有可维护性和可扩展性.并且,在进行设计的时候,也需要遵循以下几个原则:单一职责原则.开放封闭原则.里氏代替 ...

  2. 利用BootStrap Table插件实现自己的弹出框分页。

    参考链接1:    官网:http://bootstrap-table.wenzhixin.net.cn/zh-cn/home/        开始使用:http://bootstrap-table. ...

  3. 传统方式和插件方式 分别实现 分页 功能 pageHelper 插件

    实现分页  这里提供两种方式  一种是传统的分页方式  一种是基于pageHelper插件 实现的分类     推荐使用后者 前者是一般开发的方式   思路  先手动创建一个 pageUtil 工具 ...

  4. Bootstrap Paginator分页插件+ajax 实现动态无刷新分页

    之前做分页想过做淘宝的那个,但是因为是后台要求不高,就Bootstrap Paginator插件感觉还蛮容易上手,所以就选了它. Bootstrap Paginator分页插件下载地址: Downlo ...

  5. Django 实现分页功能(django 2.2.7 python 3.7.5 )

    Django 自带名为 Paginator 的分页工具, 方便我们实现分页功能.本文就讲解如何使用 Paginator 实现分页功能. 一. Paginator Paginator 类的作用是将我们需 ...

  6. bootstrap分页插件--Bootstrap Paginator的使用&AJAX版备份(可单独使用)

    html部分: <ul class="pagination"></ul> <!--bootstrap3版本用ul包裹--> <div cl ...

  7. Bootstrap Paginator 分页插件参数介绍及使用

    Bootstrap Paginator是一款基于Bootstrap的js分页插件,功能很丰富,个人觉得这款插件已经无可挑剔了.它提供了一系列的参数用来支持用户的定制,提供了公共的方法可随时获得插件状态 ...

  8. Bootstrap Paginator分页插件的使用

    今天,我为大家带来的一款做得非常优秀的分页插件BootStrap Paginator,他是一款js插件,由于本人也是才刚刚搞出来的,所以暂时对它也不是特别了解,只能大楖告诉大家怎么使用.我这里使用的是 ...

  9. Bootstrap Paginator分页插件

    Bootstrap Paginator分页插件使用示例 最近做的asp.netMVC项目中需要对数据列表进行分类,这个本来就是基于bootstrap开发的后台,因此也就想着bootstrap是否有分页 ...

随机推荐

  1. 单机部署-consul

    在本机开发环境中,直接通过以下命令可以启动一个单机consul服务器: ./consul agent -server -data-dir=/tmp/consul -bootstrap -adverti ...

  2. bzoj 2588 树上主席树

    主席树上树,对于每个节点,继承其父亲的,最后跑f[x]+f[y]-f[lca]-f[fa[lca]] 去重竟然要减一,我竟然不知道?? #include<cstdio> #include& ...

  3. LOJ_6178_景区路线规划

    LOJ_6178_景区路线规划 题意: 游乐园被描述成一张 nnn 个点,mmm 条边的无向图(无重边,无自环).每个点代表一个娱乐项目,第 iii 个娱乐项目需要耗费 cic_ic​i​​ 分钟的时 ...

  4. 用Java为Hyperledger Fabric(超级账本)编写区块链智能合约链代码

    编写第一个 Java 链代码程序 在上一节中,您已经熟悉了如何构建.运行.部署和调用链代码,但尚未编写任何 Java 代码. 在本节中,将会使用 Eclipse IDE.一个用于 Eclipse 的 ...

  5. Ubuntu18.04 Desktop Entry

    1.Desktop Entry 是什么? 我们都知道,在Windows里软件在安装的时候都会询问是不是要在开始菜单和桌面创建快捷方式,这样就不用在使用软件的时候去安装目录启动,而是直接去开始菜单点击相 ...

  6. 列表(list) ----python

    Python 列表(List) 序列是Python中最基本的数据结构.序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推. Python有6个序列的内置类型 ...

  7. 哎呀,我老大写Bug啦——记一次MessageQueue的优化

    MessageQueue,顾名思义消息队列,在系统开发中也是用的比较多的一个中间件吧.我们这里主要用它来做日志管理和订单管理的,记得老老大(恩,是的,就是老老大,因为他已经跳槽了)还在的时候,当时也是 ...

  8. TensorFlow之DNN(三):神经网络的正则化方法(Dropout、L2正则化、早停和数据增强)

    这一篇博客整理用TensorFlow实现神经网络正则化的内容. 深层神经网络往往具有数十万乃至数百万的参数,可以进行非常复杂的特征变换,具有强大的学习能力,因此容易在训练集上过拟合.缓解神经网络的过拟 ...

  9. MIPCache 域名升级

    一.MIPCache URL 是什么 举个例子,MIP 官网的 URL 为: https://www.mipengine.org 对应的 MIPCache 的 URL 为: https://mipca ...

  10. 原生JS封装 toast 弹层,自动关闭

    由于公司业务需求,要一个公共toast ,下面是自己封装的一个. css: .toast { text-align: center; min-height: 70px; width: 220px; c ...