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

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

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

    我是FE,也是Fe

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

    統(tǒng)計

    留言簿(15)

    閱讀排行榜

    評論排行榜

    javascript解析平鋪樹形數(shù)據(jù)

    在做tree封裝的時候,困難的地方往往是怎樣顯示樹形數(shù)據(jù),總后臺查詢的數(shù)據(jù)通常是List<Map<K,V>>之類的JSON字符串。形如
    [{"NODELEVEL":2,"NODENAME":"測試深度節(jié)點20","FLAG":"1","HASCHILD":"1","PARENTNODE":"10002","LEVELCODE":"1000200000"}
    ,{
    "NODELEVEL":3,"NODENAME":"測試深度節(jié)點200","FLAG":"1","HASCHILD":"1","PARENTNODE":"1000200000","LEVELCODE":"100020000000000"}
    ,{
    "NODELEVEL":4,"NODENAME":"測試深度節(jié)點2000","FLAG":"1","HASCHILD":"1","PARENTNODE":"100020000000000","LEVELCODE":"10002000000000000000"}
    ,{
    "NODELEVEL":5,"NODENAME":"測試深度節(jié)點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"}
    ]
    通常樹需要的數(shù)據(jù)是有結(jié)構(gòu)層次的,形如:
    [
       {
          
    "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":"測試深度節(jié)點20",
          
    "FLAG":"1",
          
    "HASCHILD":"1",
          
    "PARENTNODE":"10002",
          
    "LEVELCODE":"1000200000",
          
    "children":[
             {
                
    "NODELEVEL":3,
                
    "NODENAME":"測試深度節(jié)點200",
                
    "FLAG":"1",
                
    "HASCHILD":"1",
                
    "PARENTNODE":"1000200000",
                
    "LEVELCODE":"100020000000000",
                
    "children":[
                   {
                      
    "NODELEVEL":4,
                      
    "NODENAME":"測試深度節(jié)點2000",
                      
    "FLAG":"1",
                      
    "HASCHILD":"1",
                      
    "PARENTNODE":"100020000000000",
                      
    "LEVELCODE":"10002000000000000000",
                      
    "children":[
                         {
                            
    "NODELEVEL":5,
                            
    "NODENAME":"測試深度節(jié)點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

    從平鋪的格式轉(zhuǎn)換到層次結(jié)構(gòu)的json我經(jīng)過多次實踐,得出了下面的方法:

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

                    
    // 如果是一級節(jié)點,此時父節(jié)點應(yīng)該是根節(jié)點
                    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;// 保證棧中是同級節(jié)點的最后一個
                }

                
    if (previousnode.level > mapednode.level) {// 深度減少 出棧
                    for ( var j = 0; j < (previousnode.level - mapednode.level); j++) {
                        stack.pop();
                    }
                    
    // 如果回到了一級節(jié)點,此時父節(jié)點應(yīng)該是根節(jié)點
                    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;// 保證棧中是同級節(jié)點的最后一個
                }

            }
        }
        
    delete stack;
        
    delete arr;
        
    return treenodes;

    }

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

    var parsedTreeData = parse(arr,parseoption);

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

    上面的方法沒有實現(xiàn)同級節(jié)點排序,使用push方法能保證樹的同級顯示順序與深度遍歷結(jié)果中的出現(xiàn)順序(這樣可以利用ajax數(shù)據(jù)本身的順序)。其實可以用插入排序的方法來替換上面的多處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;
                }
                
    //數(shù)字比較
                if((!isNaN(targetSortValue)) && (!isNaN(sortValue)) && parseFloat(targetSortValue)>parseFloat(sortValue) ){
                    insertIndex
    = j;
                    
    break;
                }
    else{
                    insertIndex
    =j+1;
                }
            }
            parentnode.children.splice(insertIndex, 
    0, i);

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

    所以我又開始想怎么將無序的平鋪樹數(shù)據(jù)解析成層級結(jié)構(gòu)。

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

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

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

    大家在樹方面有什么建議和經(jīng)驗不妨分享分享。 相關(guān)的代碼下載

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

    評論

    # re: javascript解析平鋪樹形數(shù)據(jù) 2011-09-16 08:26 tb

    有點困難啊   回復(fù)  更多評論   

    主站蜘蛛池模板: 日本一区二区三区在线视频观看免费| 性生交片免费无码看人| 最新亚洲人成无码网www电影| 亚洲精品高清视频| 狠狠亚洲狠狠欧洲2019| 日韩免费高清视频网站| 希望影院高清免费观看视频| 美女视频黄的免费视频网页| gogo免费在线观看| 精品一区二区三区无码免费直播| 亚洲乱码在线卡一卡二卡新区| 久久青青成人亚洲精品| 亚洲一区二区三区影院| 亚洲第一黄色网址| 国产免费私拍一区二区三区| 性xxxx视频播放免费| 福利免费观看午夜体检区| 日韩亚洲国产高清免费视频| 中文字幕天天躁日日躁狠狠躁免费| 91成人免费福利网站在线| www成人免费视频| 国产99视频精品免费视频76| 一区二区三区免费在线视频 | 精品国产sm捆绑最大网免费站| 国产成人无码区免费网站| 三上悠亚在线观看免费| CAOPORN国产精品免费视频| ssswww日本免费网站片| 特级毛片aaaa免费观看| 免费无毒a网站在线观看| 十八禁的黄污污免费网站| 无人视频免费观看免费视频| 美女被吸屁股免费网站| 无码的免费不卡毛片视频| 人人爽人人爽人人片av免费| 一级毛片免费观看不收费| 美女被免费网站91色| 可以免费观看的国产视频| 一级毛片**不卡免费播| 69视频在线观看免费| 国国内清清草原免费视频99|