在前不久做的一个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最新版:修改了对汉字排序有误的问题,可以实现字母汉字混排(其实现是:将汉字转换为全拼,统一按字母排序))