最近比较忙,前期忙公司手机端接口项目,各种开发+调试+发布现在几乎上线无问题了;虽然公司项目忙不过在期间抽空做了两件个人觉得有意义的事情,一者使用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. jQuery UI resizable使用注意事项、实时等比例拉伸及你不知道的技巧

    这篇文章总结的是我在使用resizable插件的过程中,遇到的问题及变通应用的奇思妙想. 一.resizable使用注意事项 以下是我在jsfiddle上写的测试demo:http://jsfiddl ...

  2. 学点HTTP知识

    不学无术 又一次感觉到不学无术,被人一问Http知识尽然一点也没答上来,丢人丢到家了啊.平时也看许多的技术文章,为什么到了关键时刻就答不上来呢? 确实发现一个问题,光看是没有用的,需要实践.看别人说的 ...

  3. 前端框架 EasyUI (1)熟悉一下EasyUI

    jQuery EasyUI 官方网站 http://www.jeasyui.com/ .去年新开了个中文网 http://www.jeasyui.net/,不知道是不是官方的,不过看着挺像样.但是,广 ...

  4. Taurus.MVC 2.2 开源发布:WebAPI 功能增强(请求跨域及Json转换)

    背景: 1:有用户反馈了关于跨域请求的问题. 2:有用户反馈了参数获取的问题. 3:JsonHelper的增强. 在综合上面的条件下,有了2.2版本的更新,也因此写了此文. 开源地址: https:/ ...

  5. “.Net 社区虚拟大会”(dotnetConf) 2016 Day 1 Keynote: Scott Hunter

    “.Net 社区虚拟大会”(dotnetConf) 2016 今天凌晨在Channel9 上召开,在Scott Hunter的30分钟的 Keynote上没有特别的亮点,所讲内容都是 微软“.Net社 ...

  6. ExtJS 4.2 业务开发(三)数据添加和修改

    接上面的船舶管理业务,这里介绍添加和修改操作. 目录 1. 添加操作 2. 修改操作 3. 在线演示 1. 添加操作 1.1 创建AddShipWindow.js 在业务中的view目录下创建一个Ad ...

  7. OpenCASCADE Job - dimue

  8. CRL快速开发框架系列教程三(更新数据)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  9. C#中将DataTable导出为HTML的方法

    今天我要向大家分享一种将DataTable导出为到HTML格式的方法.有时我们需要HTML格式的输出数据, 以下代码就可以帮助我们达到目的,. 首先,我们要绑定DataTable和 DataGridV ...

  10. Asp.net Core 初探(发布和部署Linux)

    前言 俗话说三天不学习,赶不上刘少奇.Asp.net Core更新这么长时间一直观望,周末帝都小雨,宅在家看了下Core Web App,顺便搭建了个HelloWorld环境来尝尝鲜,第一次看到.Ne ...