最近比较忙,前期忙公司手机端接口项目,各种开发+调试+发布现在几乎上线无问题了;虽然公司项目忙不过在期间抽空做了两件个人觉得有意义的事情,一者使用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,我们需要在点击“查询”按钮的时候去调用这个插件,然后通过插件去获取后台接口返回的数据,并绑定到页面展示出来,所以有了如下代码:
1 var snTool = new shenniuTool(); 2 3 $("button[id=‘btnSearch‘]").on("click", function () { 4 5 var data = { 6 txtName: $("input[name=‘txtName‘]").val(), 7 nStatus: $("select option:selected").val(), 8 dOperateTime: $("input[name=‘dOperateTime‘]").val() 9 }; 10 11 snTool.listFun({ 12 showId: "divShowResult", //内容显示的div的Id 13 url: "/Menu/Search", 14 data: data, 15 pageSize: 2, //每页N条 16 headText: [ 17 { nickName: "全选", name: "Id", colType: "checkbox" }, 18 { nickName: "名称", name: "Name", colType: "label", isModalHeadText: true }, 19 { nickName: "链接", name: "Link" }, 20 { nickName: "状态", name: "EnableDes" }, 21 { nickName: "操作人", name: "OperatorDes" }, 22 { nickName: "操作时间", name: "OperateTime", format: "yyyy-MM-dd" }, 23 { nickName: "操作", name: "Id", colType: "operate" } 24 ], 25 editeOption: { 26 url: "/Menu/Edit", 27 title: "编辑", 28 height: 500 29 }, 30 viewOption: { 31 url: "/Menu/Details", 32 title: "查看", 33 height: 500 34 }, 35 delOption: { 36 url: "/Menu/Delete", 37 title: "删除", 38 height: 500 39 }, 40 modalExt: modalExt 41 }); 42 });
注意参数url: "/Menu/Search",这个指向的就是后台接口,那么咋们来看下我后台咋们写的:
1 [HttpGet] 2 public JsonResult Search() 3 { 4 var moPageResult = new StageModel.MoPageResult<dynamic>(); 5 6 try 7 { 8 9 var txtName = Request.Params["txtName"]; 10 var nStatus = string.IsNullOrWhiteSpace(Request.Params["nStatus"]) ? -1 : Convert.ToInt32(Request.Params["nStatus"]); 11 var dOperateTime = string.IsNullOrWhiteSpace(Request.Params["dOperateTime"]) ? Convert.ToDateTime("1991-01-01") : Convert.ToDateTime(Request.Params["dOperateTime"]); 12 var data = db.MoMenus.AsQueryable(); 13 if (!string.IsNullOrWhiteSpace(txtName)) 14 { 15 data = data.Where(b => b.Name.Contains(txtName)); 16 } 17 if (nStatus >= 0) 18 { 19 data = data.Where(b => b.IsEnable == (nStatus == (int)StageEnumHelper.ComStatus.启用)); 20 } 21 if (dOperateTime > Convert.ToDateTime("1991-01-01")) 22 { 23 data = data.Where(b => b.OperateTime >= dOperateTime && b.OperateTime < dOperateTime.AddDays(1)); 24 } 25 26 moPageResult.MoPageContent( 27 data, 28 b => b.OperateTime, 29 b => new 30 { 31 Id = b.Id, 32 Name = b.Name, 33 Link = b.Link, 34 Des = b.Des, 35 IsEnable = b.IsEnable, 36 Operator = b.Operator, 37 38 OperatorDes = b.MoUserInfo.NickName, 39 EnableDes = b.IsEnable ? "启用" : "禁用", 40 OperateTime = b.OperateTime 41 }); 42 43 } 44 catch (Exception ex) 45 { 46 } 47 return Json(moPageResult, JsonRequestBehavior.AllowGet); 48 }
后台接口Request.Params获取的几个参数就是从前端
1 2 3 4 5 |
|
传递过来的,分别代码了视图中的名称,状态,操作时间等查询条件;下面来看下,后台这儿没有看到获取类似分页的当前页数和分页记录数的操作,是封装到了MoPageResult类中的MoPageContent()中,来看下MoPageResult类代码如:
1 #region 分页数据返回 2 3 public class MoPageResult<TResult> where TResult : class, new() 4 { 5 6 public MoPageResult() 7 { 8 9 } 10 11 public IQueryable<TResult> MoResult; 12 13 /// <summary> 14 /// 总页数 15 /// </summary> 16 public int PageTotal { get; set; } 17 18 19 /// <summary> 20 /// 当前页数 21 /// </summary> 22 public int CurrentPage { get; set; } 23 24 /// <summary> 25 /// 分页记录数 26 /// </summary> 27 public int PageSize { get; set; } 28 29 /// <summary> 30 /// 分页方法 31 /// </summary> 32 /// <typeparam name="TKey"></typeparam> 33 /// <param name="query"></param> 34 /// <param name="order_desc"></param> 35 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() 36 { 37 38 if (HttpContext.Current == null) { return; } 39 var Request = HttpContext.Current.Request; 40 41 this.PageSize = string.IsNullOrWhiteSpace(Request.Params["pageSize"]) ? 15 : Convert.ToInt32(Request.Params["pageSize"]); 42 this.CurrentPage = string.IsNullOrWhiteSpace(Request.Params["currentPage"]) ? 1 : Convert.ToInt32(Request.Params["currentPage"]); 43 44 var nTotal = query.Count(); 45 this.PageTotal = nTotal / this.PageSize + (nTotal % this.PageSize > 0 ? 1 : 0); 46 47 if (selector != null) 48 { 49 if (isDesc) 50 { 51 query = query.OrderByDescending(desc); 52 } 53 else 54 { 55 query = query.OrderBy(desc); 56 } 57 this.MoResult = query. 58 Skip((this.CurrentPage - 1) * this.PageSize). 59 Take(this.PageSize). 60 Select(selector); 61 } 62 } 63 64 } 65 66 #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中,指定时间列的格式如:
1 |
|
使用format格式化时间格式,这个插件兼容的给有:yyyy,MM,dd,HH,mm,ss,相信满足大家需要了;
. 开发者视角阅读shenniu.pager.js代码
首先,我们从上而下,映入眼帘的是插件属性:
里面已经包括了注释说明,看起来应该不是问题; $.extend(defOption, option); 这段代码意思是吧用户传递进来的参数和插件里面默认的参数合并,用户大于插件直接可以覆盖相同属性的值;
再来,看请求后台的方法:
1 //请求后台 2 function ajaxFun(option) { 3 4 if (option) { 5 $.extend(defOption, option); 6 } 7 8 //获取分页参数 9 var hidPageSize = defOption.pageSize; 10 var hidCurrentPage = defOption.currentPage; 11 12 if ($("form input[name=‘pageSize‘]").val()) { 13 hidPageSize = $("form input[name=‘pageSize‘]").val(); 14 } 15 if ($("form input[name=‘currentPage‘]").val()) { 16 hidCurrentPage = $("form input[name=‘currentPage‘]").val(); 17 } 18 19 //合并用户查询条件和分页参数条件 20 var searchData = { 21 pageSize: hidPageSize, 22 currentPage: hidCurrentPage 23 }; 24 $.extend(searchData, defOption.data); 25 //请求后台数据 26 $.ajax({ 27 28 url: defOption.url, 29 type: "get", 30 data: searchData, 31 dataType: "json", 32 timeout: defOption.timeout, 33 34 async: true, 35 beforeSend: defOption.befFun, 36 success: defOption.sucFun, 37 }); 38 }
这个方法就是请求接口获取数据的方法,里面默认获取了页面中的pageSize,currentPage两个分页所需要的参数,这里采用的是get方式来请求,当然可以写成post,不过需要后台支持post就行了;
我们再看查询列表方法:
这个方法体挺长的,主要操作是:
默认格式展示列表头部并呈现出加载中的提示=》绑定复选框全选事件=》创建数据返回成功函数sucFun()=》调用请求后台方法ajaxFun();
再来看函数sucFun()等到数据返回后执行的操作是:
遍历json返回数据展示到table中(其中包括了时间格式化的处理,复选框,label及操作按钮类型operate的初始化)=》页数展示及事件绑定(目前只有上一页,当前页之前页码,当前页,当前页以后页码,下一页的效果展示,分页查询条件(生成pagesize和currentPage隐藏控件),绑定分页按钮事件)