最近比较忙,前期忙公司手机端接口项目,各种开发+调试+发布现在几乎上线无问题了;虽然公司项目忙不过在期间抽空做了两件个人觉得有意义的事情,一者使用aspnetcore开发了个人线上项目(要说线上其实只能ip访问,没有域名哈哈),其架构组成由:aspnetcore1.0.0+redis+ postgressql+TaskMainForm服务,这个项目在后期会开源出来供大家分享学习,站点地址点这里心声网;一者是目前正在做的后台管理框架一叶子,现目前刚好吧js分页插件shenniu.pager.js写完,个人觉得还是可以的,这也是本章将要和大家分享的内容;那么开始今天的分享内容,希望各位多多扫码支持:

  . 为什么采用js分页及效果图

  . 在view中如何使用及分享个后台方法

  . 开发者视角阅读shenniu.pager.js代码

下面一步一个脚印的来分享:

. 为什么采用js分页及效果图

首先,咋们来了解下市面上mvc两种常用的分页方式:跳转分页和ajax分页;跳转分页意思就是页面重定向到指定的页面并通过传递分页需要的参数,从而获取数据后通过Modal来绑定数据,这个每次都会刷下页面体验上不是很好;ajax分页通过异步js请求某个接口,然后从接口获取到数据后,再赋值到展示的界面上,这种方式是不会刷新页面,从而保证了用户体验;

下面来看下这次分享的js分页插件效果图:

图一:

图二:

图三:

看效果图好像看不出来什么东西,我只能说没办法,以后争取弄个gif动态图片吧,后面代码才是关键

. 在view中如何使用及分享个后台方法

首先,为了页面样式好看我使用了bootstrap+ace样式框架,样式效果就是如上面几张图所示(这里是样式和js文件);由于该插件是采用jquery格式书写的所以需要引用jquery.js,如上面图所示使用到了日期选择框,因为我采用的样式都是基于h5的设计所以这里引用的日期选择插件bootstrap-datepicker.min.js和她的样式bootstrap-datepicker3.min.css;该实例需要的引用文件都好了,下面看下截图:

再来,咋们就开始使用shenniu.pager.js,我们需要在点击“查询”按钮的时候去调用这个插件,然后通过插件去获取后台接口返回的数据,并绑定到页面展示出来,所以有了如下代码:

  var snTool = new shenniuTool();

         $("button[id='btnSearch']").on("click", function () {

             var data = {
txtName: $("input[name='txtName']").val(),
nStatus: $("select option:selected").val(),
dOperateTime: $("input[name='dOperateTime']").val()
}; snTool.listFun({
showId: "divShowResult", //内容显示的div的Id
url: "/Menu/Search",
data: data,
pageSize: , //每页N条
headText: [
{ nickName: "全选", name: "Id", colType: "checkbox" },
{ nickName: "名称", name: "Name", colType: "label", isModalHeadText: true },
{ nickName: "链接", name: "Link" },
{ nickName: "状态", name: "EnableDes" },
{ nickName: "操作人", name: "OperatorDes" },
{ nickName: "操作时间", name: "OperateTime", format: "yyyy-MM-dd" },
{ nickName: "操作", name: "Id", colType: "operate" }
],
editeOption: {
url: "/Menu/Edit",
title: "编辑",
height:
},
viewOption: {
url: "/Menu/Details",
title: "查看",
height:
},
delOption: {
url: "/Menu/Delete",
title: "删除",
height:
},
modalExt: modalExt
});
});

注意参数url: "/Menu/Search",这个指向的就是后台接口,那么咋们来看下我后台咋们写的:

 [HttpGet]
public JsonResult Search()
{
var moPageResult = new StageModel.MoPageResult<dynamic>(); try
{ var txtName = Request.Params["txtName"];
var nStatus = string.IsNullOrWhiteSpace(Request.Params["nStatus"]) ? - : Convert.ToInt32(Request.Params["nStatus"]);
var dOperateTime = string.IsNullOrWhiteSpace(Request.Params["dOperateTime"]) ? Convert.ToDateTime("1991-01-01") : Convert.ToDateTime(Request.Params["dOperateTime"]);
var data = db.MoMenus.AsQueryable();
if (!string.IsNullOrWhiteSpace(txtName))
{
data = data.Where(b => b.Name.Contains(txtName));
}
if (nStatus >= )
{
data = data.Where(b => b.IsEnable == (nStatus == (int)StageEnumHelper.ComStatus.启用));
}
if (dOperateTime > Convert.ToDateTime("1991-01-01"))
{
data = data.Where(b => b.OperateTime >= dOperateTime && b.OperateTime < dOperateTime.AddDays());
} moPageResult.MoPageContent(
data,
b => b.OperateTime,
b => new
{
Id = b.Id,
Name = b.Name,
Link = b.Link,
Des = b.Des,
IsEnable = b.IsEnable,
Operator = b.Operator, OperatorDes = b.MoUserInfo.NickName,
EnableDes = b.IsEnable ? "启用" : "禁用",
OperateTime = b.OperateTime
}); }
catch (Exception ex)
{
}
return Json(moPageResult, JsonRequestBehavior.AllowGet);
}

后台接口Request.Params获取的几个参数就是从前端

       var data = {
txtName: $("input[name='txtName']").val(),
nStatus: $("select option:selected").val(),
dOperateTime: $("input[name='dOperateTime']").val()
};

  传递过来的,分别代码了视图中的名称,状态,操作时间等查询条件;下面来看下,后台这儿没有看到获取类似分页的当前页数和分页记录数的操作,是封装到了MoPageResult类中的MoPageContent()中,来看下MoPageResult类代码如:

 #region  分页数据返回

         public class MoPageResult<TResult> where TResult : class, new()
{ public MoPageResult()
{ } public IQueryable<TResult> MoResult; /// <summary>
/// 总页数
/// </summary>
public int PageTotal { get; set; } /// <summary>
/// 当前页数
/// </summary>
public int CurrentPage { get; set; } /// <summary>
/// 分页记录数
/// </summary>
public int PageSize { get; set; } /// <summary>
/// 分页方法
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <param name="query"></param>
/// <param name="order_desc"></param>
public void MoPageContent<T, TKey>(IQueryable<T> query, Expression<Func<T, TKey>> desc, Expression<Func<T, TResult>> selector = null, bool isDesc = true) where T : class,new()
{ if (HttpContext.Current == null) { return; }
var Request = HttpContext.Current.Request; this.PageSize = string.IsNullOrWhiteSpace(Request.Params["pageSize"]) ? : Convert.ToInt32(Request.Params["pageSize"]);
this.CurrentPage = string.IsNullOrWhiteSpace(Request.Params["currentPage"]) ? : Convert.ToInt32(Request.Params["currentPage"]); var nTotal = query.Count();
this.PageTotal = nTotal / this.PageSize + (nTotal % this.PageSize > ? : ); if (selector != null)
{
if (isDesc)
{
query = query.OrderByDescending(desc);
}
else
{
query = query.OrderBy(desc);
}
this.MoResult = query.
Skip((this.CurrentPage - ) * this.PageSize).
Take(this.PageSize).
Select(selector);
}
} } #endregion

MoPageContent()中默认是获取了pagesize,currentpage参数,这样减少了用户操作性,并且此方法承担了计算总页数和执行分页语句的角色,注意最后查询语句Select(selector),selector是Expression<Func<T, TResult>>类型,这个T有条件约束where T : class,new();我在调用该分页类的使用传递的T是dynamic,因为赖人如我觉得匿名类更方便;唯一遗憾的是select输出暂时无法直接对某个属性直接使用方法;

最后,插件使用还需要注意一个地方,就是时间,如果后台不处理时间直接DateTime的json格式化,那么在插件获取出来的时间格式如:

这个时候就需要在使用shenniu.pager.js插件时候在属性headText中,指定时间列的格式如:

 { nickName: "操作时间", name: "OperateTime", format: "yyyy-MM-dd" }

  使用format格式化时间格式,这个插件兼容的给有:yyyy,MM,dd,HH,mm,ss,相信满足大家需要了;

. 开发者视角阅读shenniu.pager.js代码

首先,我们从上而下,映入眼帘的是插件属性:

var defOption = {

        showId: "divShowResult",  //内容显示的div
url: "", //ajax数据来源地址
headText: [
{ nickName: "A", colType: "checkbox", name: "Id" },
{ nickName: "B", colType: "label", name: "Name", isModalHeadText: true } //isModalHeadText:是否是模式窗体头部显示的信息
],
data: {}, //查询条件
editeOption: {
url: "",
title: "编辑",
width: ,
height:
}, //编辑地址,不包括id
viewOption: {
url: "",
title: "查看",
width: ,
height:
}, //查看地址
delOption: {
url: "",
title: "删除",
width: ,
height:
}, //删除地址 currentPage: , //当前页数
pageSize: , //分页记录数
showPageTab: , //展示6个页数
modalExt: null, //模式窗体对象 //可忽略
callback: function () { }, //回调函数
tabId: "tab001",
loading: "努力加载中,等会吧...", //可以直接写出<img src=''/>
sucFun: function (data) { },
befFun: function () { },
errFun: function () { },
comFun: function () { },
timeout: //超时60S
}; $.extend(defOption, option);

里面已经包括了注释说明,看起来应该不是问题; $.extend(defOption, option); 这段代码意思是吧用户传递进来的参数和插件里面默认的参数合并,用户大于插件直接可以覆盖相同属性的值;

再来,看请求后台的方法:

 //请求后台
function ajaxFun(option) { if (option) {
$.extend(defOption, option);
} //获取分页参数
var hidPageSize = defOption.pageSize;
var hidCurrentPage = defOption.currentPage; if ($("form input[name='pageSize']").val()) {
hidPageSize = $("form input[name='pageSize']").val();
}
if ($("form input[name='currentPage']").val()) {
hidCurrentPage = $("form input[name='currentPage']").val();
} //合并用户查询条件和分页参数条件
var searchData = {
pageSize: hidPageSize,
currentPage: hidCurrentPage
};
$.extend(searchData, defOption.data);
//请求后台数据
$.ajax({ url: defOption.url,
type: "get",
data: searchData,
dataType: "json",
timeout: defOption.timeout, async: true,
beforeSend: defOption.befFun,
success: defOption.sucFun,
});
}

这个方法就是请求接口获取数据的方法,里面默认获取了页面中的pageSize,currentPage两个分页所需要的参数,这里采用的是get方式来请求,当然可以写成post,不过需要后台支持post就行了;

我们再看查询列表方法

 //查询列表
listFun: function (option) { if (option) {
$.extend(defOption, option);
} //默认格式
var tab = [];
tab.push('<table id="' + defOption.tabId + '" class="table table-bordered table-hover">');
tab.push('<thead><tr role="row">'); for (var i in defOption.headText) { var head = defOption.headText[i]; if (head.colType == "label") {
tab.push('<th class="center" tabindex="0" rowspan="1" colspan="1">' + head.nickName + '</th>');
} else if (head.colType == "checkbox") {
tab.push('<th class="center " rowspan="1" colspan="1" aria-label="">');
tab.push(' <label class="pos-rel">');
tab.push(' <input type="checkbox" name="cbAll" class="ace">');
tab.push(' <span class="lbl">' + head.nickName + '</span>');
tab.push(' </label>');
tab.push('</th>');
} else {
tab.push('<th class="center" tabindex="0" rowspan="1" colspan="1">' + head.nickName + '</th>');
}
}
tab.push('</tr></thead>');
tab.push('<tbody><tr><td class="text-center" colspan="' + defOption.headText.length + '">' + defOption.loading + '</td></tr></tbody>');
tab.push('</table>');
tab.push('<div id="divPager" class="text-center"></div>');
$("#" + defOption.showId).html(tab.join(''));
//全选事件
$("input[type='checkbox'][name='cbAll']").on("click", function () { var cbStatus = $(this).is(":checked");
if (cbStatus) {
$("input[name='cb']:checkbox").prop("checked", true);
} else {
$("input[name='cb']:checkbox").prop("checked", false);
}
}); //数据返回成功处理
defOption.sucFun = function (data) { var head = $("table[id='" + defOption.tabId + "'] tbody");
if (data) {
if (data.MoResult) {
//遍历table展示的数据
var rows = [];
$.each(data.MoResult, function (i, item) {
rows.push('<tr>'); var modalHeadText = "";
for (var h_i in defOption.headText) {
var head = defOption.headText[h_i];
var item_val = item[head.name];
if (item_val && typeof (item_val) != "undefined") { } else { item_val = ""; } //时间格式化
if (head.format && item_val.length > ) {
console.log(item_val);
var date = new Date(parseInt(item_val.replace("/Date(", "").replace(")/", ""), ));
item_val = head.format.
replace("yyyy", date.getFullYear()).
replace("MM", date.getMonth() + ).
replace("dd", date.getDate()).
replace("HH", date.getHours()).
replace("mm", date.getMinutes()).
replace("ss", date.getMilliseconds());
} //获取模式窗体头部信息
if (modalHeadText.length <= ) { modalHeadText = head.isModalHeadText ? item_val : "" };
if (head.colType == "label") { rows.push('<td class="center">' + item_val + '</td>');
} else if (head.colType == "checkbox") {
rows.push('<td class="center">');
rows.push(' <label class="pos-rel">');
rows.push(' <input type="checkbox" name="cb" value="' + item_val + '" class="ace">');
rows.push(' <span class="lbl"></span>');
rows.push(' </label>');
rows.push('</td>');
} else if (head.colType == "operate") { rows.push('<td class="center"><div class="hidden-sm hidden-xs action-buttons">');
if (defOption.editeOption.url.length > ) {
var editOption = $.extend({}, defOption.editeOption);
editOption.url += "/" + item_val;
editOption.title += modalHeadText.length > ? "-" + modalHeadText : ""; var op = JSON.stringify(editOption);
rows.push('<a class="blue" data-item=\'' + op + '\' href="javascript:;"><i class="ace-icon fa fa-pencil bigger-130"></i></a>');
}
if (defOption.viewOption.url.length > ) { var viewOption = $.extend({}, defOption.viewOption);
viewOption.url += "/" + item_val;
viewOption.title += modalHeadText.length > ? "-" + modalHeadText : ""; var op = JSON.stringify(viewOption);
rows.push('<a class="blue" data-item=\'' + op + '\' href="javascript:;"><i class="ace-icon fa fa-search-plus bigger-130"></i></a>');
}
if (defOption.delOption.url.length > ) { var delOption = $.extend({}, defOption.delOption);
delOption.url += "/" + item_val;
delOption.title += modalHeadText.length > ? "-" + modalHeadText : ""; var op = JSON.stringify(delOption);
rows.push('<a class="blue" data-item=\'' + op + '\' href="javascript:;"><i class="ace-icon fa fa-trash-o bigger-130"></i></a>');
}
rows.push('</div></td>');
}
else { rows.push('<td class="center">' + item_val + '</td>');
}
}
rows.push('</tr>');
}); //页数展示
if (data.MoResult.length > ) {
var pager = [];
pager.push('<div class="text-center">');
pager.push(' <ul class="pagination" style="margin-top:0px">');
var nPager = defOption.showPageTab;//每次展示6个分页
//上一页
var nprev = (data.CurrentPage - >= ? data.CurrentPage - : );
pager.push(' <li class="paginate_button previous" aria-controls="dynamic-table" tabindex="0" id="dynamic-table_previous">');
pager.push(' <a href="javascript:;" name="npager" data-page="' + nprev + '">上一页</a>');
pager.push(' </li>'); //当前页之前页码
var preTotal = data.CurrentPage - nPager >= ? data.CurrentPage - nPager : ;
for (var i = preTotal; i < data.CurrentPage ; i++) { pager.push(' <li class="paginate_button ' + (i == data.CurrentPage ? "active disabled" : "") + '" aria-controls="dynamic-table">');
pager.push(' <a href="javascript:;" name="npager" data-page="' + i + '">' + i + '</a>');
pager.push(' </li>');
} //当前页
pager.push(' <li class="paginate_button active disabled" aria-controls="dynamic-table">');
pager.push(' <a href="javascript:;" name="npager" data-page="' + data.CurrentPage + '">' + data.CurrentPage + '</a>');
pager.push(' </li>'); //当前页以后页码
var nextTotal = data.CurrentPage + nPager > data.PageTotal ? data.PageTotal : data.CurrentPage + nPager;
for (var i = data.CurrentPage + ; i <= nextTotal; i++) { pager.push(' <li class="paginate_button ' + (i == data.CurrentPage ? "active disabled" : "") + '" aria-controls="dynamic-table">');
pager.push(' <a href="javascript:;" name="npager" data-page="' + i + '">' + i + '</a>');
pager.push(' </li>');
}
//下一页
var nnext = (data.PageTotal < data.CurrentPage + ? data.PageTotal : data.CurrentPage + );
pager.push(' <li class="paginate_button next" aria-controls="dynamic-table" tabindex="0" id="dynamic-table_next">');
pager.push(' <a href="javascript:;" name="npager" data-page="' + nnext + '">下一页</a>');
pager.push(' </li>'); pager.push(' </ul>');
//分页查询条件
pager.push('<div style="display:none">');
pager.push(' <form>');
pager.push(' <input type="hidden" name="pageSize" value="' + defOption.pageSize + '"/>');
pager.push(' <input type="hidden" name="currentPage" value="' + defOption.currentPage + '"/>');
pager.push(' </form>');
pager.push('</div>'); pager.push('</div>'); //移除加载中
//head.html("");
//添加结果
head.html(rows.join(''));
$("div[id='divPager']").html(pager.join(''));
//操作按钮事件
$("a[data-item]").on("click", function () { var data_Item = $(this).attr("data-item");
if (data_Item) {
var data_Item_Obj = JSON.parse(data_Item); defOption.modalExt.modalFun({
width: data_Item_Obj.width,
height: data_Item_Obj.height,
url: data_Item_Obj.url,
title: data_Item_Obj.title,
callback: defOption.callback
});
}
});
//绑定分页按钮事件
$("a[name='npager']").on("click", function () { var nPager = $(this).attr("data-page");
if (nPager.length <= ) { return; } $("form input[name='currentPage']").val(nPager); //执行请求后台
ajaxFun(defOption);
});
} else {
head.html("<tr><td class=\"text-center\" colspan=\"" + defOption.headText.length + "\">未能查询到数据!</td></tr>");
$("div[id='divPager']").html("");
}
} else {
head.html("<tr><td class=\"text-center\" colspan=\"" + defOption.headText.length + "\">未能查询到数据。</td></tr>");
$("div[id='divPager']").html("");
}
} else {
head.html("<tr><td class=\"text-center\" colspan=\"" + defOption.headText.length + "\">未能查询到数据</td></tr>");
$("div[id='divPager']").html("");
}
};
if (option) {
$.extend(defOption, option);
} //执行请求后台
ajaxFun(defOption);
}

这个方法体挺长的,主要操作是:

默认格式展示列表头部并呈现出加载中的提示=》绑定复选框全选事件=》创建数据返回成功函数sucFun()=》调用请求后台方法ajaxFun();

再来看函数sucFun()等到数据返回后执行的操作是:

遍历json返回数据展示到table中(其中包括了时间格式化的处理,复选框,label及操作按钮类型operate的初始化)=》页数展示及事件绑定(目前只有上一页,当前页之前页码,当前页,当前页以后页码,下一页的效果展示,分页查询条件(生成pagesize和currentPage隐藏控件),绑定分页按钮事件)

以上就是shenniu.pager.js整个插件内容,不多且清晰,感觉分享给大家挺高兴,下面贴出示例中用到的js文件和css文件可以在这里下载

MVC如何使用开源分页插件shenniu.pager.js的更多相关文章

  1. jQuery分页插件(jquery.page.js)的使用

    效果描述: 不用分页即可显示的jQuery插件 jQuery分页插件——jQuery.page.js用法很简单,效果很棒   1.前端   首先html的head中引入相关css与js <lin ...

  2. 分页插件jquery.simplePagination.js使用

    利用ecshop后台,利用插件更改分页显示样式遇到的问题,由于是利用Ajax获取数据进行页面数据更新?所以出现了以下情况: 初始化页面前 : 分页更新后: 点击后出现了分页插件内容消失, 原因:分页一 ...

  3. 分页插件 jquery.pagination.js

    引用 <script src="http://www.jq22.com/jquery/jquery-1.10.2.js"></script> <lin ...

  4. 使用jQuery的分页插件jquery.pagination.js进行分页

    1,需要用到jquery.pagination.js和pagination.css https://pan.baidu.com/s/1G3PLQSRGjvLxl2ryqpV76w https://pa ...

  5. JS无刷新分页插件

    本文介绍一个本人自己写的一JS分页插件 <script src="/Js/smart.page.min.js" type="text/javascript" ...

  6. Mybatis的PageHelper分页插件的PageInfo的属性参数,成员变量的解释,以及页面模板

    作者:个人微信公众号:程序猿的月光宝盒 //当前页 private int pageNum; //每页的数量 private int pageSize; //当前页的数量 private int si ...

  7. 基于存储过程的MVC开源分页控件

    基于存储过程的MVC开源分页控件--LYB.NET.SPPager 摘要 现在基于ASP.NET MVC的分页控件我想大家都不陌生了,百度一下一大箩筐.其中有不少精品,陕北吴旗娃杨涛大哥做的分页控件M ...

  8. 分页插件--根据Bootstrap Paginator改写的js插件

    刚刚出来实习,之前实习的公司有一个分页插件,和后端的数据字典约定好了的,基本上是看不到内部是怎么实现的,新公司是做WPF的,好像对于ASP.NET的东西不多,导师扔了一个小系统给我和另一个同事,指了两 ...

  9. Bootstrap Paginator分页插件

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

随机推荐

  1. vue双向数据绑定原理探究(附demo)

    昨天被导师叫去研究了一下vue的双向数据绑定原理...本来以为原理的东西都非常高深,没想到vue的双向绑定真的很好理解啊...自己动手写了一个. 传送门 双向绑定的思想 双向数据绑定的思想就是数据层与 ...

  2. jq选择器基础

    Jquery $代表选择器 使用jq必须要导入jq文件 <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js&qu ...

  3. .NET设计模式访问者模式

    一.访问者模式的定义: 表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作. 二.访问者模式的结构和角色: 1.Visitor 抽象访问者角色,为该 ...

  4. java面向对象六原则一法则

    1. 单一职责原则:一类只做它该做的事. 2. 里氏替换原则:子类必须能够替换基类(父类),否则不应当设计为其子类. 3. 依赖倒换原则:设计要依赖于抽象而不是具体化. 4. 接口隔离原则:接口要小而 ...

  5. 如何获取url中的参数并传递给iframe中的报表

    在使用报表软件时,用户系统左边一般有目录树,点击报表节点就会在右侧网页的iframe中显示出报表,同时点击的时候也会传递一些参数给网页,比如时间和用户信息等.如何使网页中的报表能够获取到传递过来的参数 ...

  6. Storm

    2016-11-14  22:05:29 有哪些典型的Storm应用案例? 数据处理流:Storm可以用来处理源源不断流进来的消息,处理之后将结果写入到某个存储中去.不像其它的流处理系统,Storm不 ...

  7. C#迪杰斯特拉算法

    C#迪杰斯特拉算法 网上有许多版本的,自己还是写一个理解点 Dijkstra.cs public class Dijkstra { private List<Node> _nodes; p ...

  8. linux下mono,powershell安装教程

    1简介 简单来说pash就是bash+powershell 2官网 https://github.com/Pash-Project/Pash 3下载fedora20---lxde桌面---32位版. ...

  9. 新手如何在gdb中存活

    网络上已经有很多gdb调试的文章了,为什么我还要写这篇文章呢,因为本文是写给gdb新手的,目的就是通过一个简单的例子来让新手很快上手.一旦上手入门了,其他的问题就可以自己去搜索搞定了.右边是gdb的L ...

  10. 在C#代码中应用Log4Net系列教程(附源代码)

    Log4Net应该可以说是DotNet中最流行的开源日志组件了.以前需要苦逼写的日志类,在Log4Net中简单地配置一下就搞定了.没用过Log4Net,真心不知道原来日志组件也可以做得这么灵活,当然这 ...