在前不久做的一个web项目中,需要实现js表格排序的效果,当时为了省事,就在网上找了几个相关的js插件,像:jQuery的table排序插件(感觉其使用比较麻烦或不清楚其具体用法,就没有使用)、原生态js的table排序插件等,最后比较看了下——采用了一个原生态js的table排序插件,并在其基础上做了些修改,虽有些勉强或有些地方使用不太舒服,但最算是比较好的实现了当时需要的功能。而前两天,对原有表格做了点儿修改——增加隔行换色的功能,问题就出现了,——效果错乱;检查分析了下,问题出在其table排序插件代码上——其原代码写的比较难理解,修改还不如重新自己写一个table排序插件。
说写就写,table排序其实很简单:就是取出所有排序列的值并存放在数组中(并且各列对应行对象也存放到一个数组中),然后对排序列的值数组排序(并对行对象数组排序)。下面贴出table排序插件代码:
1 /** 2 * @description 表格排序实现 3 * @author Blog:http://www.cnblogs.com/know/ 4 * @date 2011-10-28 5 * @modify date 2012-12-08 6 * @modify description 修改了对汉字排序有误的问题,可以实现字母汉字混排(其实现是:将汉字转换为全拼,统一按字母排序) 7 **/ 8 (function () { 9 //#region 全局变量 10 //初始化配置对象 11 var _initConfig = null; 12 var _tableObj = null, _tbodyObj = null, _tBodyIndex = 0; 13 //存放当前各排序方式下的(有序)行数组的对象——仅在IsLazyMode=true,此变量有用 14 var _trJqObjArray_Obj = null; 15 //#endregion 16 17 //#region 内部方法 18 /** 19 * 获得排序列值数组的方法 20 * @private 21 * @param trJqObjArr:(外部传入)存放排序行的数组,tdIndex:排序列的索引,td_valAttr:排序列的取值属性,td_dataType:排序列的值类型 22 **/ 23 function GetOrderTdValueArray(trJqObjArr, tdIndex, td_valAttr, td_dataType) { 24 var tdOrderValArr = new Array(); 25 var trObj, tdObj, tdVal; 26 _tbodyObj.find("tr").each(function (trIndex, trItem) { 27 trObj = $(trItem); 28 trJqObjArr.push(trObj); 29 30 tdObj = trObj.find("td")[tdIndex]; 31 tdObj = $(tdObj); 32 tdVal = td_valAttr ? tdObj.attr(td_valAttr) : tdObj.text(); 33 tdVal = GetValue(tdVal, td_dataType); 34 tdOrderValArr.push(tdVal); 35 }); 36 return tdOrderValArr; 37 } 38 39 /** 40 * 返回jQuery对象的方法 41 * @private 42 **/ 43 function GetJqObj(id) { 44 return "string" == typeof (id) ? $("#" + id) : $(id); 45 }; 46 47 /** 48 * 排序方法 49 * @private 50 * @param tdIndex:排序列的索引,options:排序列的规则配置对象 51 **/ 52 function Sort(tdIndex, options) { 53 var trJqObjArr = null; 54 if (_initConfig.IsLazyMode) { 55 !_trJqObjArray_Obj && (_trJqObjArray_Obj = {}); 56 trJqObjArr = _trJqObjArray_Obj[tdIndex]; 57 } 58 var isExist_trJqObjArr = true; 59 if (!trJqObjArr) { 60 isExist_trJqObjArr = false; 61 trJqObjArr = new Array(); 62 var tdOrderValArr = GetOrderTdValueArray(trJqObjArr, tdIndex, options.ValAttr, options.DataType); 63 var sort_len = tdOrderValArr.length - 1; 64 var isExchanged = false, compareRes; 65 for (var i = 0; i < sort_len; i++) { 66 isExchanged = false; 67 for (var j = sort_len; j > i; j--) { 68 compareRes = options.Desc ? (tdOrderValArr[j] > tdOrderValArr[j - 1]) : (tdOrderValArr[j] < tdOrderValArr[j - 1]); 69 if (compareRes) { 70 ExchangeArray(tdOrderValArr, j); 71 //交换行对象在数组中的顺序 72 ExchangeArray(trJqObjArr, j); 73 isExchanged = true; 74 } 75 } 76 //一遍比较过后如果没有进行交换则退出循环 77 if (!isExchanged) 78 break; 79 } 80 _initConfig.IsLazyMode && (_trJqObjArray_Obj[tdIndex] = trJqObjArr); 81 } 82 83 if (trJqObjArr) { 84 if (options.Toggle) { 85 _initConfig.IsLazyMode && isExist_trJqObjArr && trJqObjArr.reverse(); 86 options.Desc = !options.Desc; 87 } 88 ShowTable(trJqObjArr); 89 } 90 } 91 92 /** 93 * 显示排序后的表格 94 * @private 95 * @param trJqObjArr:排序后的tr对象数组 96 **/ 97 function ShowTable(trJqObjArr) { 98 for (var n = 0, len = trJqObjArr.length; n < len; n++) { 99 _tbodyObj.append(trJqObjArr[n]); 100 $.isFunction(_initConfig.OnShow) && (_initConfig.OnShow(n, trJqObjArr[n], _tbodyObj)); 101 } 102 } 103 104 /** 105 * 交换数组中项的方法 106 * @private 107 * @param array:数组,j:交换数组项的尾项索引 108 **/ 109 function ExchangeArray(array, j) { 110 var temp = array[j]; 111 array[j] = array[j - 1]; 112 array[j - 1] = temp; 113 } 114 115 /** 116 * 添加排序方式(规则)的方法 117 * @private 118 * @param tdVal:排序列的值,td_dataType:排序列的值类型 119 **/ 120 function GetValue(tdVal, td_dataType) { 121 switch (td_dataType) { 122 case "int": 123 return parseInt(tdVal) || 0; 124 case "float": 125 return parseFloat(tdVal) || 0; 126 case "date": 127 return Date.parse(tdVal) || 0; 128 case "string": 129 default: 130 { 131 var tdVal = tdVal.toString() || ""; 132 //如果值不为空,获得值是汉字的全拼 133 if (tdVal) { 134 tdVal = ZhCN_Pinyin.GetQP(tdVal); 135 tdVal = tdVal.toLowerCase(); 136 } 137 return tdVal; 138 } 139 } 140 } 141 142 /** 143 * 添加排序方式(规则)项的方法 144 * @private 145 * @param obj:排序触发(标签)的对象或id,index:要排序列所在的列索引,options:排序规则设置对象(如:DataType...) 146 **/ 147 function SetOrderItem(obj, index, options) { 148 var orderSettings = { 149 ValAttr: false, //排序列的取值属性,默认为:innerText 150 DataType: "string", //排序列的值类型(可取值:int|float|date|string) 151 OnClick: null, //(点击)排序时触发的方法 152 Desc: true, //(是否是降序)排序方式,默认为:降序 153 Toggle: true, //切换排序方式 154 DefaultOrder: false //是否是默认的排序方式 155 }; 156 $.extend(orderSettings, options); 157 orderSettings.DataType = orderSettings.DataType.toLowerCase(); 158 obj = GetJqObj(obj); 159 //绑定触发排序的事件 160 obj.bind("click", function () { 161 Sort(index, orderSettings); 162 $.isFunction(orderSettings.OnClick) && orderSettings.OnClick(); 163 }); 164 orderSettings.DefaultOrder && Sort(index, orderSettings); 165 } 166 //#endregion 167 168 //#region 对外公开 169 var _api = { 170 Init: function (obj, tBodyIndex, options) { 171 /// <summary>初始化方法</summary> 172 /// <param name="obj" type="Object">要排序table的id或对象</param> 173 /// <param name="tBodyIndex" type="int">要排序的数据行所在的tbody标签的索引</param> 174 /// <param name="options" type="Object">初始化配置对象,{IsLazyMode:是否是懒惰模式,OnShow: 排序后表格显示时的方法}</param> 175 if (obj == null || typeof (obj) == undefined) { 176 alert("TableOrder初始化参数为空或有误!"); 177 return; 178 } 179 if (typeof (ZhCN_Pinyin) == undefined) { 180 alert("获得汉字首拼的'ZhCN_Pinyin'对象不存在!"); 181 return; 182 } 183 _tableObj = GetJqObj(obj); 184 _tBodyIndex = tBodyIndex || 0; 185 _tbodyObj = _tableObj.find("tbody:eq(" + _tBodyIndex + ")"); 186 options = options || {}; 187 _initConfig = { 188 IsLazyMode: true, //是否是懒惰模式,默认为:true 189 OnShow: null //排序后表格显示时的方法,params:trIndex,trJqObj,tbodyObj 190 }; 191 $.extend(_initConfig, options); 192 _trJqObjArray_Obj = null; 193 }, 194 SetOrder: function (obj, index, options) { 195 /// <summary>设置排序规则的方法</summary> 196 /// <param name="obj" type="Object">排序触发(标签)的对象或id</param> 197 /// <param name="index" type="int">要排序列所在的列索引</param> 198 /// <param name="options" type="Object">排序规则设置对象(如:DataType...)</param> 199 if (_tableObj == null) { 200 alert("_tableObj尚未初始化!"); 201 return; 202 } 203 SetOrderItem(obj, index, options); 204 } 205 }; 206 window.TableOrderOper = _api; 207 //#endregion 208 })();
其使用如下:
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> 5 <title>table表格排序</title> 6 <style type="text/css"> 7 .fu_list{ width:500px; border:1px solid #ebebeb;line-height:20px; font-size:12px;} 8 .fu_list thead td{background-color:#ebebeb;} 9 .fu_list td{padding:5px;} 10 .fu_list a{outline:none;/*ff*/hide-focus:expression(this.hideFocus=true);/*ie*/} 11 .fu_list a:link, .fu_list a:visited, .fu_list a:hover, .fu_list a:active{text-decoration:none;color:#333;} 12 .fu_list thead a{padding-right:15px;} 13 .fu_list thead a.up, .fu_list thead a.down{ background:url() right center no-repeat; } 14 .fu_list thead a.down{background-image:url();} 15 16 .hoverTr{background-color:Orange;} 17 </style> 18 </head> 19 <body> 20 <table border="0" cellspacing="0" cellpadding="0" class="fu_list" id="idTable"> 21 <thead> 22 <tr> 23 <td> <a href="javascript:void(0)" id="idTitle">名称</a> / <a href="javascript:void(0)" id="idExt">类型</a></td> 24 <td width="150" align="center"><a href="javascript:void(0)" id="idAddtime" class="up">上传时间</a></td> 25 <td width="50" align="center"><a href="javascript:void(0)" id="idSize">大小</a></td> 26 </tr> 27 </thead> 28 <tbody> 29 <tr> 30 <td _order="JSCSS">JSCSS</td> 31 <td align="center" _order="2008/9/12 8:51:09">2008/9/12 8:51:09</td> 32 <td align="right" _order="433247">433247</td> 33 </tr> 34 <tr> 35 <td _order="逗你玩">逗你玩</td> 36 <td align="center" _order="2008/3/6 20:12:23">2008/3/6 20:12:23</td> 37 <td align="right" _order="11394">11394</td> 38 </tr> 39 <tr> 40 <td _order="张迪">张迪</td> 41 <td align="center" _order="2008/10/4 20:21:54">2008/10/4 20:21:54</td> 42 <td align="right" _order="351">351</td> 43 </tr> 44 <tr> 45 <td _order="Index">Index</td> 46 <td align="center" _order="2008/10/4 20:24:11">2008/10/4 20:24:11</td> 47 <td align="right" _order="14074">14074</td> 48 </tr> 49 <tr> 50 <td _order="阿波罗">阿波罗</td> 51 <td align="center" _order="2008/10/4 20:24:11">2008/10/4 20:24:11</td> 52 <td align="right" _order="2844">2844</td> 53 </tr> 54 <tr> 55 <td _order="张涛">张涛</td> 56 <td align="center" _order="2012/10/4 20:21:54">2012/10/4 20:21:54</td> 57 <td align="right" _order="1236">1236</td> 58 </tr> 59 <tr> 60 <td _order="jSSon">jSSon</td> 61 <td align="center" _order="2010/12/12 8:51:09">2010/12/12 8:51:09</td> 62 <td align="right" _order="10101">10101</td> 63 </tr> 64 </tbody> 65 </table> 66 <script src="jquery-1.4.1.min.js" type="text/javascript"></script> 67 <script src="TableOrder.js" type="text/javascript"></script> 68 <script src="ZhCN_Pinyin.min.js" type="text/javascript"></script> 69 <script type="text/javascript"> 70 TableOrderOper.Init("idTable", 0, { 71 OnShow: function (i, trJqObj, _tbodyObj) { 72 trJqObj.attr("class", ((i + 1) % 2 == 0 ? "hoverTr" : "")); 73 } 74 }); 75 TableOrderOper.SetOrder("idTitle", 0, { ValAttr: "_order", DataType: "string" }); 76 TableOrderOper.SetOrder("idAddtime", 1, { ValAttr: "_order", DataType: "date" }); 77 TableOrderOper.SetOrder("idSize", 2, { DataType: "int", DefaultOrder: true, OnClick: function () { 78 alert("idSize"); 79 } }); 80 </script> 81 </body> 82 </html>
代码中注释我都尽量写的比较清楚了,需要补充说明的是:
1.js使用的是闭包,我强调代码要尽可能的简洁易懂。
2.IsLazyMode属性设置,IsLazyMode=true,适用于当前要排序的表格是不变的,即不会有ajax的增删改行的操作,而且你看代码后就可以看出的一个好处:把要排序列的对应的行对象只一次遍历,并将排序后的行对象数组保存在全局对象中,下次排序时直接通过tdIndex(排序列的索引)取出对应的行对象数组,并将数组反转,即可实现排序的效果,可以在一定程度上提高代码执行效率(性能); IsLazyMode=false, 即适用于当前要排序的表格会改变,如有ajax的增删改行的操作的情况。
3.考虑一般要排序的表格数据量都不大,其中的数组排序使用的是冒泡排序算法。
4.OnShow: null //排序后表格显示时的方法,params:trIndex,trJqObj,tbodyObj ——可方便用于设置排序后的表格的换行样式等,也出于对性能优化方面的考虑。
好了,最后,附上插件js和demo,目前的实现只能说是能很好的满足我当前项目中的需求或适用于于大多数的场景,如果有没有考虑到或不好的地方,希望各位路过的朋友,能毫不客气的拍砖留言,大家互相交流学习!
Demo下载(2012-12-08最新版:修改了对汉字排序有误的问题,可以实现字母汉字混排(其实现是:将汉字转换为全拼,统一按字母排序))