项目中用到了Pagination分页栏插件.很精简的一个插件,但是只提供分页栏显示的功能.
如果使用ajax来翻页的话,用起来不太方便.所以打算自己扩展下,前台做的少,js不太好,欢迎大家指点 :-)
例如: 如下使用
$("#pagination_div").pagination(totalSize, {callback:function(nextIndex){ $.ajax({ type : "POST", url : "http://www.baidu.com", data : {page:(nextIndex+1), rows:"10"}, success : function(html) { $("#page_table_tbody").html("").append(html); } }); }}
这样每个用到分页的地方都需要写一次ajax请求,而且返回的html数据需要在后台处理好,如果是json数据的还需要自己去处理,挺麻烦的.
而且现在经常会出现这种情况,后台的分页方法只有一个,返回json数据,然后需要用到的地方解析json,展示哪些属性由前端渲染界面的时候来决定. 所以为了少点重复劳动, 对它扩展了一下.
原本是打算直接改Pagination源码的,但是感觉不太好,一个是怕改出问题,影响到原来已经使用了的地方,一个是升级啥的比较麻烦(虽然感觉这个插件应该不会升级了:-) ). 所以后面决定在另外的js文件中实现功能,然后通过callback将他们两者联系起来.
先说说大概思路:
1.解析json数据和dom的操作属于重复劳动,需要抽象出来.
那么如何抽象出来呢? 列和后台对象的属性如何Mapping起来, 用过JQuery EasyUI的人都知道,它的表格初始化的时候都需要将列的显示名, 对应后台哪个属性(简单的说就是哪一列显示哪个属性)等等的配置在组件初始化的时候传入.
这里我也是使用的这种方法.于是我们写table的时候需要加上一些配置信息,例如:
<table id="table_id"> <thead head> <tr> <th name="id">主键</th> <th name="name">姓名</th> <th name="link">操作</th> </tr> </thead> <tbody data></tbody> </table>
这个时候,th的name属性值,就对应着后台对象的属性
好了,现在映射对应起来,但是还有些问题, 很多情况下,表格中都包含一列,用来放按钮,链接等东西,而这些东西并不是后台的属性,而是通过后台属性动态生成的数据. 这个时候怎么办呢? 而且我们经常有的需求就是对日期,金钱等的格式化等等操作.
很容易想到的就是在处理后台json数据的时候回调一下用户定义的函数. 那么有哪些地方需要回调呢?
1.每一行(tr)生成后. 2.每一个单元格(td)完成后. 3.ajax网络错误处理回调. 4.全部处理完成回调 5.单击回调......
如果要做的很灵活的话,就要有很多回调的地方,但是现在项目需求并不是很复杂....提供1,2,3,4的功能就好...其他的有需求了再加,原理是一样的,就是在配置的时候提供回调函数,然后在对应的地方回调.
回调的需要注意的是this对象的使用.如果碰到古怪的问题了,往这方面想象(-.-)
好了,现在要将回调传给我们的组件,我们才能回调到~~! 其他的回调都好说,在初始化组件的时候传进去就好, 但是每一个单元格(td)的回调,就不太好传了..........后面想了个蛋疼的办法 如下面代码所示:
<th name="link" opts="{handler:function(index, data, td){ var a = $('<a>查看</a>'); a.attr('href',' + data.id); a.appendTo(td); }}">操作</th>
有点蛋疼,不过没办法...毕竟对于我现在的项目来说,这个情况少,哈哈哈哈哈哈哈,要不做成初始化的时候传也行.
这里handler函数的 index表示当前是第几行, data是后台数据的json对象(某一行的), td是td标签对应的JQuery对象在最后我们会将td这个对象appendTo(tr).
那么怎么将这些配置给初始化到我们的组件中呢? 我的做法:
$.PageProcesser = function(tableId, url, pageSize, opts){ var that = this; this.tableId = tableId;//table的id,必须的 this.url = url; //ajax请求数据的url必须的 this.pageSize = pageSize ? pageSize : 10; //每页显示条数 if(!tableId || !url){ throw "PageProcesser : the param tableId and url are required"; } //初始化参数,rowHandler是每行处理完后的回调函数,参数和上面说的类似,提供一个默认配置 //param参数是为了这种情况:ajax请求的时候有其他的请求参数..... this.opts = jQuery.extend({ param:{}, rowHandler:function(index, data, tr){return true;},}, opts||{} ); //这个是初始化每一类的配置,包括列对应的属性名,列的位置(1,2,3,4,5),列的处理回调函数 //因为上面td的配置方式,所以这里用eval了,求勿喷 :-) this.tdOpts = []; $("#" + tableId + " th[name]").each(function(index, element){ var fieldName = $(this).attr("name"); var fieldOpts = $(this).attr("opts"); fieldOpts = fieldOpts ? eval("fieldOpts = " + fieldOpts) : {}; fieldOpts = jQuery.extend({handler:function(index, data, td){return true;}}, fieldOpts); that.tdOpts.push({name:fieldName, index:index, opts:fieldOpts}); }); };
好了,现在构造函数定义好了. 初始化类似于这样:
//第一个参数是table的id, 第二个:ajax请求路径, var pageHaper = new $.PageProcesser("table", "${path}/json", 100, { param:{type:"1"}, //ajax请求附带的参数 rowHandler:function(index, data, tr){//行处理回调 index % 2 == 0 ? tr.css("color", "red") : ""; } });
好了,参数定义及初始化都好了,现在来定义方法. 如下代码:
$.extend($.PageProcesser.prototype, { callback:function(page_index, pagination){//代理pagination的回调函数 this.requester(page_index); //ajax请求函数 return false; }, requester:function(page){//ajax请求数据 var requestParam = jQuery.extend({page:(page+1), rows:this.pageSize}, this.opts.param); //注意设置context:this 防止ajax回调函数中this调用不到handlerJson方法. $.ajax({ type : "POST", url : this.url, data : requestParam, context:this, success : function(json) { this.handlerJson(json); } }); }, handlerJson:function(json){//根据后台json和配置更新dom var datas = json ? (json.rows ? json.rows : []) : [] ; var tbody = $("#" + this.tableId + " tbody[data]"); tbody.html("");//清空原来的数据 for(var i=0 ; i<datas.length ; i++){//循环json中的数组,创建tr,td,并调用对应的回调 var tr = $("<tr></tr>"); for(var j=0 ; j<this.tdOpts.length ; j++){ var val = datas[i][this.tdOpts[j].name]; var td = $("<td></td>").text(val); this.tdOpts[j].opts.handler(i, datas[i], td);//回调列处理器 td.appendTo(tr);//这里可以写成批量的方式来提高效率.... } this.opts.rowHandler(i, datas[i], tr);//回调用户行处理器 tr.appendTo(tbody);//这里也可以写成批量的方式来提高效率.... } }, });
好了,都搞完了,现在来用用看(还有些功能没有实现,比如ajax网络错误,应该有对应的处理,等等地方...我懒)
现在看看完整的代码:
/** * jquery插件,用来扩展jquery分页插件, * 该插件做以下事情: * 1.$.ajax.post异步请求数据,数据格式{rows:[]}; * 2.将获取到的数据根据配置生成tbody内容 */ (function($){ $.PageProcesser = function(tableId, url, pageSize, opts){ var that = this; this.tableId = tableId; this.url = url; this.pageSize = pageSize ? pageSize : 10; if(!tableId || !url){ throw "PageProcesser : the param tableId and url are required"; } this.opts = jQuery.extend({ param:{}, rowHandler:function(index, data, tr){return true;},}, opts||{} ); this.tdOpts = []; $("#" + tableId + " th[name]").each(function(index, element){ var fieldName = $(this).attr("name"); var fieldOpts = $(this).attr("opts"); fieldOpts = fieldOpts ? eval("fieldOpts = " + fieldOpts) : {}; fieldOpts = jQuery.extend({handler:function(index, data, td){return true;}}, fieldOpts); that.tdOpts.push({name:fieldName, index:index, opts:fieldOpts}); }); }; $.extend($.PageProcesser.prototype, { callback:function(page_index, pagination){//pagination的回调函数 this.requester(page_index); return false; }, requester:function(page){//ajax请求数据 var requestParam = jQuery.extend({page:(page+1), rows:this.pageSize}, this.opts.param); $.ajax({ type : "POST", url : this.url, data : requestParam, context:this, success : function(json) { this.handlerJson(json); } }); }, handlerJson:function(json){ var datas = json ? (json.rows ? json.rows : []) : [] ; var tbody = $("#" + this.tableId + " tbody[data]"); tbody.html(""); for(var i=0 ; i<datas.length ; i++){ var tr = $("<tr></tr>"); for(var j=0 ; j<this.tdOpts.length ; j++){ var val = datas[i][this.tdOpts[j].name]; var td = $("<td></td>").text(val); this.tdOpts[j].opts.handler(i, datas[i], td); td.appendTo(tr); } this.opts.rowHandler(i, datas[i], tr); tr.appendTo(tbody); } }, }); })(jQuery);
使用:
$(function() { var pageHaper = new $.PageProcesser("table", "${path}/json", 10, { param:{type:"1"}, rowHandler:function(index, data, tr){//双行变红 index % 2 == 0 ? tr.css("color", "red") : ""; } }); $("#page_bar").pagination(100,{callback:function(pageIndex, pagination){ return pageHaper.callback(pageIndex, pagination); } }); });
<table id="table" style="border: 1px; width: 50%; text-align: center;"> <thead head> <tr> <th name="id">主键</th> <th name="name">姓名</th> <th name="link" opts="{handler:function(index, data, td){ var a = $('<a>'); a.attr('href','http://www.baidu.com/'); a.text('删除:' + data.id); a.appendTo(td); }}">操作</th> </tr> </thead> <tbody data></tbody> </table> <div id="page_bar" style="margin-top: 50px;"></div>
效果:
后台代码(Spring mvc):
@ResponseBody @RequestMapping(value = "/json") public Object testJson(Integer page, Integer rows){ PageInfo<Map<String, String>> pageInfo = new PageInfo<Map<String,String>>(page, rows); pageInfo.setRows(getMapList(pageInfo)); return pageInfo; } private List<Map<String, String>> getMapList(PageInfo<?> pageInfo){ List<Map<String, String>> rows = new ArrayList<Map<String,String>>(); for (int i = pageInfo.getBegin(); i < pageInfo.getEnd()*pageInfo.getPageNo(); i++) { HashMap<String, String> map = new HashMap<String, String>(); map.put("id", "id" + i); map.put("name", "name" + i); rows.add(map); } return rows; }
PageInfo代码: /** * 分页 实体类 (封装分页请求和结果数据) */ public class PageInfo<T> implements Serializable { private static final long serialVersionUID = 5367449251268716436L; public static final int DEFAULT_PAGE_SIZE = 10; /** 分页信息 */ private int pageSize = DEFAULT_PAGE_SIZE; // 每页记录条数 private int pageNo = 1; // 页码 从1开始 /** 查询参数 **/ private Map<String, Object> paramMap = new HashMap<String, Object>(); //查询条件 private Object paramObj; //查询对象 /** 结果数据 */ private Integer total; // 总记录数 private List<T> rows; // 当前页显示数据 private boolean plugin = false; //是否走分页插件 private String sqlId; //用于标识具体执行的分页标识 public PageInfo() { super(); } public PageInfo(Integer pageNo, Integer pageSize) { this.pageNo = pageNo != null ? pageNo : 1; this.pageSize = pageSize != null ? pageSize : PageInfo.DEFAULT_PAGE_SIZE; } public PageInfo(Integer pageNo, Integer pageSize, Object paramObj) { this.pageNo = pageNo != null ? pageNo : 1; this.pageSize = pageSize != null ? pageSize : PageInfo.DEFAULT_PAGE_SIZE; this.paramObj = paramObj;//防止sql配置文件中空判断时报空指针 } /** * 获取分页begin参数 limit {begin}, {end} */ @JsonIgnore public int getBegin() { Integer begin = (pageNo - 1) * pageSize; if (begin < 0) { begin = 0; } return begin; } /** * 获取分页end参数 limit {begin}, {end} */ @JsonIgnore public int getEnd() { if (pageSize <= 0) { return DEFAULT_PAGE_SIZE; } else { return pageSize; } } //get set 方法略 改JsonIgnore的都忽略吧, }
需要注意的是:安全问题,后台数据显示到前台一定要过滤或者编码,否则容易有xss安全问题.
以上皆为原创,转载请注明!