表格排序

先展开一下表格排序的思路:

  1. 获取表格的DOM引用来定位数据行 ————(获取到要排序的表格id,通过id获取到表格的tbody,html中要写成thead和tbody,把头部和数据区分开来,然后获取到行rows)
  2. 创建一个数组,将迭代tr元素并将它们放入数组中————(a.排序有sort()方法,此方法是对数组,但是rows是个DOM集合,并非数组,需要注意,解决方案就是创建一个数组。b.放入数组中不会从表格删除tr,其存储的是指针,不是实际元素)
  3. 对数组进行排序————(用sort(),但需要注意,sort()默认的是对字符的ASCII码顺序排列,只对准字符串,不适用数字、日期等....)
  4. 使用DOM将行按顺序逐个放置————(排列好之后发现页面顺序没变?改变顺序后要将每一行按序放回,这样数据多的时候就会影响性能,我们可以采用创建文档碎片,使用appendChild()给其传入一个文档碎片,最后添加的是碎片的所有子节点,并非碎片本身。下面附带为什么影响性能)

解释一些函数、词义及原因:

sort() 方法用于对数组的元素进行排序,

  arrayObject.sort(sortby)   

  sortby可选,规定排序顺序,必须是函数。

  调用该方法时没有使用参数,是按照字符编码的顺序进行排序。要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以便进行比较。如果需要其他类型需要转换成对应的(一般用到得有整数、浮点数、日期,字符串)

  如果想按照其他标准进行排序,就需要提供比较函数sortby,该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。比较函数应该具有两个参数 a 和 b,其返回值如下:

  • 若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。
  • 若 a 等于 b,则返回 0。
  • 若 a 大于 b,则返回一个大于 0 的值。

  reverse() 方法用于颠倒数组中元素的顺序。

 

js操纵DOM数据多的时候为什么会影响性能?解决办法是什么?

  javascript操作dom是一个很耗性能的过程,在某些情况下,不得不进行dom循环操作,我们每次对dom的操作都会触发"重排",这严重影响到能耗,一般通常采取的做法是尽可能的减少dom操作来减少"重排"。

  面对循环操作dom的过程,我们选择使用文档碎片(creatDocumentFragment),将需要添加到dom中的内容一次性添加到文档碎片中,然后将文档碎片添加到dom树,这样就可以有效的减少操作dom的次

 

什么是文档碎片?最后追加到页面的是否为文档碎片本身?

文档碎片:类似一个临时的文档,要所有要加的dom元素先放在这里,达到不要每次操作dom元素
创建方法:document.createDocumentFragment()

 createdocumentfragment()方法创建了一虚拟的节点对象,节点对象包含所有属性和方法。

 当你想提取文档的一部分,改变,增加,或删除某些内容及插入到文档末尾可以使用createDocumentFragment() 方法。

 你也可以使用文档的文档对象来执行这些变化,但要防止文件结构被破坏,createDocumentFragment() 方法可以更安全改变文档的结构及节点。

 使用appendChild(),传给他一个文档碎片,最后添加的是碎片的所有子节点,并非碎片本身

 

传参的时候用到了闭包,什么是闭包?

  较规范的解释是:所谓闭包,就是指此法表示包括不必计算的变量函数,也就是说,该函数能使用函数外定义的变量,在ECMAScript中使用全局变量就是一个简单的闭包。此代码中用到了一个较复杂的闭包,在一个函数中定义另外一个函数。

function generateCompareTRs(iCol,sDataType){    

    return function compareTRs(oTR1,oTR2){

        var vValue1=convert(oTR1.cells[iCol].firstChild.nodeValue,sDataType);

        var vValue2=convert(oTR2.cells[iCol].firstChild.nodeValue,sDataType);

        

        //return sValue1.localeCompare(sValue2);

        if(vValue1<vValue2){

            return -1;

        }else if(vValue1>vValue2){

            return 1;

        }else{

        return 0;

        }

        };

}    
闭包

 

怎么给oTable添加其它的属性?用来保存排列的列索引

  document.expando用于设置或获取表明是否可对象内创建任意变量的值

  document.expando = false;此时,你在页面里面标签配置的默认属性之外的其他属性都将视为无效。//默认是true

  代码中例:oTable.sortCol=iCol;

 

代码:

 1 <table id="tableSort">  

 2     <thead>  

 3         <tr>  

 4             <th width="30%" onclick="sortTable('tableSort' , 0, 'int')"><span class="sort_able">会员ID</span></th>  

 5             <th width="30%" onclick="sortTable('tableSort' , 1)"><span class="sort_able">会员名</span></th>  

 6             <th onclick="sortTable('tableSort' , 2 , 'date')"><span class="sort_able">注册时间</span></th>  

 7         </tr>  

 8     </thead>  

 9     <tbody>  

10         <tr>  

11             <td>16</td>  

12             <td>webw3c</td>  

13             <td>2011-04-13</td>  

14         </tr>  

15         <tr>  

16             <td>45</td>  

17             <td>test001</td>  

18             <td>2011-03-27</td>  

19         </tr>  

20         <tr>  

21             <td>116</td>  

22             <td>wuliao</td>  

23             <td>2011-04-01</td>  

24         </tr>  

25         <tr>  

26             <td>29</td>  

27             <td>tired</td>  

28             <td>2011-04-06</td>  

29         </tr>  

30         <tr>  

31             <td>155</td>  

32             <td>tiredso</td>  

33             <td>2011-04-06</td>  

34         </tr>  

35         <tr>  

36             <td>31</td>  

37             <td>javascript</td>  

38             <td>2011-04-08</td>  

39         </tr>  

40         <tr>  

41             <td>132</td>  

42             <td>jquery</td>  

43             <td>2011-04-12</td>  

44         </tr>  

45     </tbody>  

46 </table>  
html
//获取表格的DOM引用来定位数据行

function sortTable(sTableID , iCol,sDataType){

    var oTable=document.getElementById(sTableID);

    var oTBody=oTable.tBodies[0];

    var colDataRows=oTBody.rows;

    

    //创建一个数组,将tr元素放入其中,这样不会从表格中删除tr元素,存储的指针

    var aTRs=new Array;

    for(var i=0;i<colDataRows.length;i++){

        aTRs.push(colDataRows[i]);

        }

    



    //逆序时,判断索引是否与最后一次排序的列索引相同

    if(oTable.sortCol==iCol){

        aTRs.reverse();

        }else{

        aTRs.sort(generateCompareTRs(iCol,sDataType));    //对aTRs排序

        }

    

    //对每一行按序放回,实现此操作最快的为创建文档碎片,将所有的tr元素按照正确顺序附加其上

    //使用文档碎片在某些情况下可以提高页面效率。

    var oFragment=document.createDocumentFragment();

    for(var i=0;i<aTRs.length;i++){

        oFragment.appendChild(aTRs[i]);

        }

    oTBody.appendChild(oFragment);

    oTable.sortCol=iCol;

    }

    

//比较函数

function generateCompareTRs(iCol,sDataType){    

    return function compareTRs(oTR1,oTR2){

        var vValue1=convert(oTR1.cells[iCol].firstChild.nodeValue,sDataType);

        var vValue2=convert(oTR2.cells[iCol].firstChild.nodeValue,sDataType);

        

        //return sValue1.localeCompare(sValue2);

        if(vValue1<vValue2){

            return -1;

        }else if(vValue1>vValue2){

            return 1;

        }else{

        return 0;

        }

        };

}    



    

//针对多种类型

function convert(sValue,sDataType){

    switch(sDataType){

        case"int":

            return parseInt(sValue);

        case"float":

            return parseFloat(sValue);

        case"date":

            return new Date(Date.parse(sValue));

        default:

            return sValue.toString();

            

        }

    }    

    

    
js

这样做需要在html代码中添加onclick,不太完美,稍后修改....

 

————————————————————————————————————————

之前的代码因为需要在html中添加点击事件,很不方便,就修改了一下,修改之后通过种种方法将代码升级,尽可能提高代码性能与减少代码的数量

这里贴上修改后js代码:

window.onload = function(){

    var oTable=document.getElementById("tableSort");

    oTable.addEventListener ("click" , fnclick , false);

    function fnclick(e){

        var x = e.target;

        if(x.nodeName.toLowerCase() === 'th'){

           sortTable("tableSort" , x.cellIndex)

        }

    }



};



//获取表格的DOM引用来定位数据行

function sortTable(sTableID , iCol){

    var oTable=document.getElementById(sTableID);

    var oTBody=oTable.tBodies[0];

    var colDataRows=oTBody.rows;

    

    var aTRs=new Array;

    for(var i=0;i<colDataRows.length;i++){

        aTRs.push(colDataRows[i]);

        }

    //排序

    if(oTable.sortCol==iCol){

        aTRs.reverse();

        }else{

        aTRs.sort(generateCompareTRs(iCol));    

        }

    var oFragment=document.createDocumentFragment();

    for(var i=0;i<aTRs.length;i++){

        oFragment.appendChild(aTRs[i]);

        }

    oTBody.appendChild(oFragment);

    oTable.sortCol=iCol;

    }

    

    

//比较函数

function generateCompareTRs(iCol){

    return function compareTRs(oTR1,oTR2){

        var vValue1=oTR1.cells[iCol].firstChild.nodeValue;

        var vValue2=oTR2.cells[iCol].firstChild.nodeValue;

        if(!isNaN(vValue1) && !isNaN(vValue2)){

            return parseInt(vValue1) - parseInt(vValue2);

        }

        return vValue1.localeCompare(vValue2);

        };

}

    



    
修改之后的js代码

 

这个是修改第三遍的代码,第二遍的时候用到了获取th的class的值,因为javascript中并没有获取class值的方法,所以多添加了一个函数,这里贴出通过javascript获取class的函数

function getElementsByClassName(className, node, tag){

    node = node || document;//如果省略了参数node,就从document中搜索,否则从node节点开始搜索

    if(node.getElementsByClassName) 

        return node.getElementsByClassName(className);

    else{

        tag = tag || "*";

        var searchElems = [];

        var elems = node.getElementsByTagName(tag);

        for(i=0; i<elems.length; i++){

            var elem = elems[i];

            if(elem.className.indexOf(className) != -1)

                searchElems.push(elem);

        }

        return searchElems;

    }

}
通过javascript获取class

第二遍时window.onload的函数是:

window.onload = function(){

    var sortCols = getElementsByClassName("sort_able");

    //sortCols.addEventListener ("click" , fnclick , false);

    for(i=0; i<sortCols.length; i++){

        var sortCol = sortCols[i];

        sortCol.onclick = function(){

            sortTable("tableSort" , this.parentNode.cellIndex)

        };

    }

};

这里可以看出和第三遍的区别是,获取class,通过for循环遍历每一列的th,点击对应th时响应函数,为什么在第三遍换成了把绑定事件绑在了tableSort上,想起来昨天总结的事件机制大量的事件绑定,性能消耗,而且还需要解绑(IE会泄漏)),因此通过冒泡来解决此问题,这样也不用获取class的值了,少了好大一段代码呢,嘿嘿....

不过html页面内容需要稍微修改一下,把span去掉包括class,因为获取事件目标,if(x.nodeName.toLowerCase() === 'th')不然这句匹配事件目标时,匹配到的就是span了

相比第一次的代码,还调整了一下转换函数,第一次的转换函数是比较精确,但是数据类型需要手动添加,我自己去判断没弄出来,很纠结....干脆就直接换掉了,代码也省去了好多,参数sDataType就不用了,他会直接判断,数字,时间,字符串问题也都解决了

突然想到另外的问题,

  1. 附加事件addEventListener(),它是DOM的附加事件的方法,IE与DOM不同,addEventListener()IE9以下不适用,
  2. IE与DOM获取事件的目标也不一样  IE:var oTarget=oEvent.srcElement;  DOM: var oTarget=oEvent.target;
  3. 点击事件也不一样,IE在附加事件中点击事件需要写为“onclick”,DOM为“click”

除了这里用到的顺便贴出其它IE与DOM的不同

  4、获取字符代码(随后添加例子吧,今天没精力了...)

  5、阻止某个事件的默认行为

  6、停止事件复制(冒泡)

还要进一步改代码......万恶的IE啊.....

终极代码

注意window.onload中代码的更改,代码可能还有待提高的地方吧,有些知识自己还没学到,还需要继续学js,随后发现再更改吧,四遍了,呜呜.....

window.onload = function(){

    var oTable=document.getElementById("tableSort");

    var clickType="click";

    if(oTable.addEventListener){

         oTable.addEventListener(clickType,fnclick,false);

       }else if(oTable.attachEvent){

         oTable.attachEvent('on'+clickType,fnclick);

       }else{

         oTable['on'+clickType]=fnclick;

       }

    //oTable.addEventListener ("click" , fnclick , false);

    function fnclick(e){

        var x = e.target;

        if(x.nodeName.toLowerCase() === 'th'){

           sortTable("tableSort" , x.cellIndex)

        }

    }

};



//获取表格的DOM引用来定位数据行

function sortTable(sTableID , iCol){

    var oTable=document.getElementById(sTableID);

    var oTBody=oTable.tBodies[0];

    var colDataRows=oTBody.rows;

    

    var aTRs=new Array;

    for(var i=0;i<colDataRows.length;i++){

        aTRs.push(colDataRows[i]);

        }

    //排序

    if(oTable.sortCol==iCol){

        aTRs.reverse();

        }else{

        aTRs.sort(generateCompareTRs(iCol));    

        }

    var oFragment=document.createDocumentFragment();

    for(var i=0;i<aTRs.length;i++){

        oFragment.appendChild(aTRs[i]);

        }

    oTBody.appendChild(oFragment);

    oTable.sortCol=iCol;

    }

    

    

//比较函数

function generateCompareTRs(iCol){

    return function compareTRs(oTR1,oTR2){

        var vValue1=oTR1.cells[iCol].firstChild.nodeValue;

        var vValue2=oTR2.cells[iCol].firstChild.nodeValue;

        if(!isNaN(vValue1) && !isNaN(vValue2)){

            return parseInt(vValue1) - parseInt(vValue2);

        }

        return vValue1.localeCompare(vValue2);

        };

}

    



    
js终极代码

 

 

 

 

 

你可能感兴趣的:(排序)