<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    我是FE,也是Fe

    前端來源于不斷的點滴積累。我一直在努力。

    統計

    留言簿(15)

    閱讀排行榜

    評論排行榜

    javascript解析平鋪樹形數據

    在做tree封裝的時候,困難的地方往往是怎樣顯示樹形數據,總后臺查詢的數據通常是List<Map<K,V>>之類的JSON字符串。形如
    [{"NODELEVEL":2,"NODENAME":"測試深度節點20","FLAG":"1","HASCHILD":"1","PARENTNODE":"10002","LEVELCODE":"1000200000"}
    ,{
    "NODELEVEL":3,"NODENAME":"測試深度節點200","FLAG":"1","HASCHILD":"1","PARENTNODE":"1000200000","LEVELCODE":"100020000000000"}
    ,{
    "NODELEVEL":4,"NODENAME":"測試深度節點2000","FLAG":"1","HASCHILD":"1","PARENTNODE":"100020000000000","LEVELCODE":"10002000000000000000"}
    ,{
    "NODELEVEL":5,"NODENAME":"測試深度節點20000","FLAG":"1","HASCHILD":"1","PARENTNODE":"10002000000000000000","LEVELCODE":"1000200000000000000000000"}
    ,{
    "NODELEVEL":6,"NODENAME":"qwerfga","FLAG":"1","HASCHILD":"0","PARENTNODE":"1000200000000000000000000","LEVELCODE":"100020000000000000000000000001"}
    ,{
    "NODELEVEL":2,"NODENAME":"sdfg","FLAG":"1","HASCHILD":"1","PARENTNODE":"10002","LEVELCODE":"1000200001"}
    ,{
    "NODELEVEL":3,"NODENAME":"safsdfsadfaaa","FLAG":"1","HASCHILD":"0","PARENTNODE":"1000200001","LEVELCODE":"100020000100001"}
    ]
    通常樹需要的數據是有結構層次的,形如:
    [
       {
          
    "NODELEVEL":2,
          
    "NODENAME":"sdfg",
          
    "FLAG":"1",
          
    "HASCHILD":"1",
          
    "PARENTNODE":"10002",
          
    "LEVELCODE":"1000200001",
          
    "children":[
             {
                
    "NODELEVEL":3,
                
    "NODENAME":"safsdfsadfaaa",
                
    "FLAG":"1",
                
    "HASCHILD":"0",
                
    "PARENTNODE":"1000200001",
                
    "LEVELCODE":"100020000100001"
             }
          ],
          
    "isFolder":true
       },
       {
          
    "NODELEVEL":2,
          
    "NODENAME":"測試深度節點20",
          
    "FLAG":"1",
          
    "HASCHILD":"1",
          
    "PARENTNODE":"10002",
          
    "LEVELCODE":"1000200000",
          
    "children":[
             {
                
    "NODELEVEL":3,
                
    "NODENAME":"測試深度節點200",
                
    "FLAG":"1",
                
    "HASCHILD":"1",
                
    "PARENTNODE":"1000200000",
                
    "LEVELCODE":"100020000000000",
                
    "children":[
                   {
                      
    "NODELEVEL":4,
                      
    "NODENAME":"測試深度節點2000",
                      
    "FLAG":"1",
                      
    "HASCHILD":"1",
                      
    "PARENTNODE":"100020000000000",
                      
    "LEVELCODE":"10002000000000000000",
                      
    "children":[
                         {
                            
    "NODELEVEL":5,
                            
    "NODENAME":"測試深度節點20000",
                            
    "FLAG":"1",
                            
    "HASCHILD":"1",
                            
    "PARENTNODE":"10002000000000000000",
                            
    "LEVELCODE":"1000200000000000000000000",
                            
    "children":[
                               {
                                  
    "NODELEVEL":6,
                                  
    "NODENAME":"qwerfga",
                                  
    "FLAG":"1",
                                  
    "HASCHILD":"0",
                                  
    "PARENTNODE":"1000200000000000000000000",
                                  
    "LEVELCODE":"100020000000000000000000000001"
                               }
                            ],
                            
    "isFolder":true
                         }
                      ],
                      
    "isFolder":true
                   }
                ],
                
    "isFolder":true
             }
          ],
          
    "isFolder":true
       }
    ]
    //ps:感謝 http://jsonformatter.curiousconcept.com/ 在線format json

    從平鋪的格式轉換到層次結構的json我經過多次實踐,得出了下面的方法:

    最開始,我約定ajax請求能得到樹深度遍歷結果,推薦之前一篇文件:一種能跨數據庫的樹形數據表格設計 上面的示例數據就是一個深度遍歷結果。深度遍歷結果的特點是每條記錄的上一條記錄要么是兄弟節點,要么是父節點,每條記錄的下一條記錄要么是兄弟節點,要么是子節點。根據這個特點,可以用如下方法解析:
    function parse(arr, option) {
        
    var treenodes = [];//存放解析結果
        var stack = [];//存放當前節點路徑 如果A->B->C-D 遍歷到D節點時stack應該是[A,B,C]
        for ( var i = 0; i < arr.length; i++) {
            
    var mapednode = arr[i];
            
    if (i == 0) {// 第一個節點
                treenodes.push(mapednode);
                stack.push(mapednode);
            } 
    else {
                
    var previousnode = arr[i - 1];
                
    if (parseInt(previousnode.level, 10+ 1 == parseInt(mapednode.level, 10)) {// 深度增加(深度增加1才視為深度增加)
                    var parentnode = stack[stack.length - 1];//棧的最后一個節點是父節點
                    parentnode.isFolder = true;
                    
    if (!parentnode.children) parentnode.children = [];
                    parentnode.children.push(mapednode);
                    stack.push(mapednode);
                }
                
    if (previousnode.level == mapednode.level) {// 與之前節點深度相同
                    // 棧中最后一個節點此時是同級節點previousnode
                    // 所以此處去父節點時需要取到previousnode的父節點

                    
    // 如果是一級節點,此時父節點應該是根節點
                    if (stack.length > 1) {
                        
    var parentnode = stack[stack.length - 2];
                        parentnode.isFolder 
    = true;
                        
    if (!parentnode.children)
                            parentnode.children 
    = [];
                        parentnode.children.push(mapednode);
                    } 
    else {
                        treenodes.push(mapednode);
                    }
                    stack[stack.length 
    - 1= mapednode;// 保證棧中是同級節點的最后一個
                }

                
    if (previousnode.level > mapednode.level) {// 深度減少 出棧
                    for ( var j = 0; j < (previousnode.level - mapednode.level); j++) {
                        stack.pop();
                    }
                    
    // 如果回到了一級節點,此時父節點應該是根節點
                    if (stack.length > 1) {
                        
    var parentnode = stack[stack.length - 2];
                        parentnode.isFolder 
    = true;
                        
    if (!parentnode.children) {
                            parentnode.children 
    = [];
                        }
                        parentnode.children.push(mapednode);
                    } 
    else {
                        treenodes.push(mapednode);
                    }

                    stack[stack.length 
    - 1= mapednode;// 保證棧中是同級節點的最后一個
                }

            }
        }
        
    delete stack;
        
    delete arr;
        
    return treenodes;

    }

    var parseoption={
        titlefield:
    "NODENAME",//顯示名稱字段
        keyfield:"LEVELCODE",//節點唯一標識字段
        levelfield:"NODELEVEL",//深度字段
        parentfield:"PARENTNODE",//父節點標識字段
        customsiblingsort:"NODENAME"//同級節點排序字段
    };

    var parsedTreeData = parse(arr,parseoption);

    基本思路是將arr循環,然后將節點層級的“塞”到對應的地方。因為總是要跟前一個節點數據比較,所以需要訪問到上一個節點。而且總需要獲得當前節點的父節點,而且需要判斷是不是回到了一級節點,所以需要記錄當前節點的訪問路徑,從整個深度遍歷arr的過程看,當前節點的路徑剛好是一個先進先出的關系,所以將stack聲明為一個堆棧使用。

    上面的方法沒有實現同級節點排序,使用push方法能保證樹的同級顯示順序與深度遍歷結果中的出現順序(這樣可以利用ajax數據本身的順序)。其實可以用插入排序的方法來替換上面的多處push。

    //插入排序法
            var cl= parentnode.children.length;
            
    var insertIndex = 0;
            
    for ( var j = 0; j < cl; j++) {
                
    var targetSortValue = arr[parentnode.children[j]][fSIBLINGSORT]||"";
                
    //字符串比較
                if(isNaN(targetSortValue) && isNaN(sortValue) && targetSortValue.localeCompare(sortValue)>0 ){
                    insertIndex
    = j;
                    
    break;
                }
    else{
                    insertIndex
    =j+1;
                }
                
    //數字比較
                if((!isNaN(targetSortValue)) && (!isNaN(sortValue)) && parseFloat(targetSortValue)>parseFloat(sortValue) ){
                    insertIndex
    = j;
                    
    break;
                }
    else{
                    insertIndex
    =j+1;
                }
            }
            parentnode.children.splice(insertIndex, 
    0, i);

    但是事實上用戶老會抱怨為什么一定要深度遍歷的結果,雖然,在之前提到的一種跨數據庫的數據表設計中比較容易獲取到深度遍歷結果。

    所以我又開始想怎么將無序的平鋪樹數據解析成層級結構。

    function parse(arr,option){
        
    //有同級排序 拼接同級節點排序函數
        if(option.customsiblingsort){
            
    if(typeof(window[option.customsiblingsort])!="function"){//不是函數,視為字段名
                var sortfield = option.customsiblingsort;
                option.customsiblingsort
    = function(node1,node2){
                    
    var v1 =node1[sortfield]||"";
                    
    var v2 =node2[sortfield]||"";
                    
    if((!isNaN(v1)) && (!isNaN(v2))){//數字比較
                        return parseFloat(v1)- parseFloat(v2);
                    }
    else{
                        
    return v1.localeCompare(v2);//字符串比較
                    }
                };
            }
    else{
                option.customsiblingsort
    =window[option.customsiblingsort];
            }
            
        }
        
    //step1:排序,按照節點深度排序,同深度節點按照customsiblingsort排序
        arr.sort(function (node1,node2){
            
    if((node1[option.levelfield]-node2[option.levelfield])>0){
                
    return 1;
            }
    else if ((node1[option.levelfield]-node2[option.levelfield])==0 && node1[option.parentfield].localeCompare(node2[option.parentfield])>0){
                
    return 1;
            }
    else if ( option.customsiblingsort  && (node1[option.levelfield]-node2[option.levelfield])==0 && node1[option.parentfield].localeCompare(node2[option.parentfield])==0 && option.customsiblingsort(node1,node2)>0 ){
                
    return 1;
            }
    else{
                
    return 0;
            }
        });
        
        
    var result  =[];
        
    var mapnode ={};//key :node key,value:node object reference
        //step2:排序后節點解析成樹
        for(var i= 0;i<arr.length;i++){
            
    var mapednode =arr[i];
            
    var n  = mapednode;
            
    //深度為1或者深度與排序后第一個節點的深度一致視為一級節點
            if(n[option.levelfield]==1 ||  n[option.levelfield]==arr[0][option.levelfield]){
                result.push(n);
                mapnode[n[option.keyfield]]
    = n;
                
    continue;
            }
            
    if(n[option.levelfield]>=1){
                
    //找到父節點
                mapnode[n[option.keyfield]]= n;
                
    var p= n[option.parentfield];
                
    var parentNode = mapnode[p];
                
    //arr是按照深度排序,任何一個節點的父節點都會在子節點之前,所以parentNode!=null
                if(typeof(parentNode.children)=="undefined"){
                    parentNode.children
    =[];
                }
                parentNode.isFolder
    =true;
                parentNode.children.push(n);
                
            }
        }
        
    delete arr,mapnode;
        
    return result;
    }

    var parseoption ={titlefield:"NODENAME",keyfield:"LEVELCODE",levelfield:"NODELEVEL",parentfield:"PARENTNODE",customsiblingsort:"NODENAME"};

    var parsedTreeData = parse(arr,parseoption);

    這種方法的循環次數自然比第一種方法要長,先根據深度將數組排序,這樣做的目的一個是保證在遍歷數組的任何一個節點是能在之前的節點中找到其父節點,第二也附帶著將同級節點的排序也實現了。這種方法代碼可讀性比一種直接,性能慢在第一階段的排序上。

    樹的前端顯示總是能對前端開發者造成很大的挑戰,光解析數據就會費勁心思。為了不至于要使用xtree,dtree那樣的傳統的tree控件,還是找找jQuery插件。目前發現了兩個不錯的jQuery tree插件jsTree 和dynatree 。不過都版本還是比較低,都不是很穩定,經常會有bug。jsTree就支持無序的數組數據源,dynatree必須是層次數據源。dynatree的性能顯然要比jsTree要好,支持lazyLoad。所以選定dynatree。只是需要自己解析數據。

    大家在樹方面有什么建議和經驗不妨分享分享。 相關的代碼下載

    posted on 2011-01-13 16:40 衡鋒 閱讀(2888) 評論(1)  編輯  收藏 所屬分類: javascriptWeb開發

    評論

    # re: javascript解析平鋪樹形數據 2011-09-16 08:26 tb

    有點困難啊   回復  更多評論   

    主站蜘蛛池模板: 亚洲另类无码专区丝袜| 中文在线免费看视频| 免费观看午夜在线欧差毛片| 国产亚洲人成在线影院| 国产成人亚洲综合无码精品| 曰批视频免费30分钟成人| 色噜噜噜噜亚洲第一| 亚洲精品成人av在线| 免费黄色小视频网站| 永久免费不卡在线观看黄网站 | 亚洲人成依人成综合网| 无人影院手机版在线观看免费| 九九久久精品国产免费看小说 | 四虎在线最新永久免费| 国产成人亚洲毛片| 亚洲香蕉免费有线视频| 亚洲免费视频一区二区三区| 成人福利免费视频| 两性色午夜视频免费网| 亚洲熟妇无码一区二区三区导航| 亚洲无人区午夜福利码高清完整版| 青青草a免费线观a| 日韩免费高清播放器| 丰满亚洲大尺度无码无码专线| 亚洲高清国产AV拍精品青青草原| 暖暖免费高清日本一区二区三区| 日本免费大黄在线观看| 一级全免费视频播放| 亚洲日韩国产一区二区三区在线| 国产l精品国产亚洲区在线观看| 好爽好紧好大的免费视频国产| 久久国产精品成人片免费| 一级毛片人与动免费观看| 亚洲欧美日韩综合俺去了| 亚洲黄色在线观看| 亚洲国产精品嫩草影院在线观看| 国产高清免费在线| 成人免费无码大片A毛片抽搐 | 亚洲中文无码永久免费| 18女人水真多免费高清毛片 | 国产片免费在线观看|