zoukankan      html  css  js  c++  java
  • 表格排序

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

    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终极代码
     
  • 相关阅读:
    第二次冲刺周期站立会议(3)
    第二次冲刺周期站立会议(2)
    第二次冲刺周期站立会议(1)
    测试计划
    对各组第一次冲刺周期的评价
    团队绩效评估计划
    学校网站UI设计分析
    站立会议(10)
    Bower和Gulp集成前端资源
    Laravel的学习网站推荐
  • 原文地址:https://www.cnblogs.com/lpshan/p/4593084.html
Copyright © 2011-2022 走看看