表格排序

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

  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终极代码

 

 

 

 

 

posted @ 2015-06-22 11:42  夏目の-の  阅读(282)  评论(0编辑  收藏  举报