自寫 zTree搜索功能 -- 關鍵字查詢 -- 遞歸無限層


嘮叨一哈

  前兩天朋友跟我說要一個ztree的搜索功能,我劈頭就是一巴掌:這種方法難道無數前輩還做少了?自己去找,我很忙~然后我默默地蹲着寫zTree的搜索方法去了。為什么呢?因為我說了句“找不到是不可能的啊,肯定有很多人早做了無數了,找不到我給你寫還請你恰午飯”,然而我也去找了很久也沒有找到(淚崩,我的計划,我的午飯~)。絕大多數都是用的API里面的getNodesByParamFuzzy()或者高亮之類的。然而朋友表示需求不符合:1. 匹配失敗父節點也隱藏;2.能自定義匹配規則,即能匹配name還能匹配屬性......(反正就是我想要的不是辣個,小生臉上笑嘻嘻,心里.......那我給你寫唄~),下面進入正文:

思維導圖

  

  一般搜索功能只是在“既定范圍內(方便稱呼)”匹配關鍵字,“既定范圍”即我們已經知道搜索的范圍:比如說一個文本庫,一個下拉框,換而言之我們匹配的對象集大小已經確定了。然而這一點在ztree上不可行,為什么呢?在我考慮了一下ztree搜索功能實現邏輯的時候問了一句:那啥,這棵樹的層級是固定的嗎?還是說不確定有多少層?老哥看着我會心一笑:你按無限層來寫~小生小腿肚子一抽。。因為樹的層級不確定,所以搜索范圍不確定,舉個栗子:目標節點匹配成功,如果這個節點是子節點,那么它的父節點也應該是顯示的,然后它父節點的父節點也應該是顯示的,然后它父節點的父節點的父節點的...Orz...這仿佛永遠寫不到盡頭了...沒辦法,只能:遞歸,找到目標節點的所有父節點和子節點。

邏輯關鍵點

  在上面的思維導圖中我大致列出了邏輯,目標節點在什么情況下顯示,什么情況下隱藏,這是我們必須清楚的關鍵點,下面我們具體看下目標節點存在的情況:

  

  到了這里,相信對於如何實現滿足我們需求的搜索功能開發,已經能做到了然於心了,剩下的只是實現的方法,然而這完全不是事~(小生竊以為真正讓人憂心的理不清功能的流程,至於實現方法你們都懂的吧?0.0..)

關於樹節點

  要完成上述流程中各種方法,我們需要知道樹節點的一系列屬性,我們都知道有api這種神器,然而api有一個特點就是齊全(齊全得我們想精確的找到某一個屬性或者方法時可能得一頓好找),這里我們想要的是如何快速得到自己想要的屬性或者方法,我們在控制台打印出樹節點集合:

  

        var treeObj=$.fn.zTree.getZTreeObj("homeTree"); // 設置根節點
        var node = treeObj.getNodes(); // 獲取根節點
        var nodes = treeObj.transformToArray(node); // 獲取所有節點
        console.log(nodes);    

 

   看圖:我們能看到所有節點,其中有id,name等各種屬性

  再看圖:我們能看到任意節點的各種屬性,有我們想要的子節點集合 childern,父節點屬性 isParent ,節點id tId,父節點id parentTid...

萬事俱備,動手

  下面看一下相關方法,很多小細節需要在真正編碼過程中才能發現,這里為了方便展示就直接列舉方法了。

  聲明備用數組:

    // 地區搜索
    var parentArray = [];
    var childArray = [];

   遞歸獲取目標節點父節點集合:

    // 遞歸獲取目標節點所有父節點
    function getParentsNode(treeNode){
        var thisParentNode = treeNode.getParentNode(); //得到該節點的父節點
        if( thisParentNode != null ){ // 父節點存在
            parentArray.push(thisParentNode); // 儲存至數組
            getParentsNode(thisParentNode); // 重調 
        }else{
            return false;
        }           
    }

   遞歸獲取目標節點子節點集合:

    // 遞歸獲取目標節點所有子節點
    function getChildrenNode(treeNode){
        var thisIsParent = treeNode.isParent; // 獲取目標節點 isParent 屬性,判斷是否為父節點
        if( thisIsParent == true ){
            var thisChildrenNode = treeNode.children; // 得到該節點的子節點集合
            for(var i=0;i<thisChildrenNode.length;i++){
                childArray.push(thisChildrenNode[i]); // 將該子節點加入數組中
                getChildrenNode(thisChildrenNode[i]); // 重調       
            }
        }else{
            return false;
        }
    }

 

  這里建議將匹配節點部分摘出來單獨寫一個方法,方便進行拓展匹配規則,這里我們假設除了匹配name還需要匹配節點的 entity_code 屬性:

    //匹配節點
    function matchNode(treeNode,num){
        var inputArea = $("input[name='searchArea']");
        var name = treeNode.name;
        var entityCode = treeNode.entity_code|| '';
        var val = inputArea.val(); // 獲取檢索值
        var numName = name.indexOf(val);
        var numCode = entityCode.indexOf(val);
        var num = -1;
        if( numName != -1 || numCode !=-1 ){
            num = 1;
        }
        if( numName == -1 && numCode == -1 ){
            num = -1;   
        }
        return num;
    }

 

   節點匹配成功方法:

    // 節點匹配成功
    function checkTrueArray(arr,treeNode){
        var thisTid = treeNode.tId;
        var thisLi = $("#"+thisTid);
        for(var n=0;n<arr.length;n++){
            var thisNodeId = arr[n].tId;
            var thisNodeLi = $("#"+thisNodeId);
            thisLi.show();
            thisNodeLi.show();
        }
    }

 

  節點匹配失敗方法:

    // 節點匹配失敗
    function checkFalseArray(arr,treeNode){
        var result = [];
        var result2 = [];
        var thisTid = treeNode.tId;
        var thisLi = $("#"+thisTid);
        var val = inputArea.val(); // 獲取檢索值
        var thisParent =  treeNode.getParentNode();  // 獲取目標節點父節點
        if( thisParent != null ){  // 有父節點
            var thisBrotherArr =  treeNode.getParentNode().children; // 得到包含自身的兄弟數組
            for(var m=0;m<arr.length;m++){ // 匹配父節點
                var num = matchNode(arr[m]);
                if( num != -1 ){
                    result.push(arr[m]);
                }
            }
            var resultLength = result.length;
            for( var m=0;m<thisBrotherArr.length;m++ ){ // 匹配兄弟節點
                var num = matchNode(thisBrotherArr[m]);
                if( num != -1 ){
                    result2.push(thisBrotherArr[m]);
                }
            }
            var resultLength2 = result2.length;
            // 對於自身匹配失敗的節點,要顯示必須滿足有父節點匹配成功,且兄弟級節點都匹配失敗
            if( (resultLength == 0 && resultLength2 == 0) || resultLength2 != 0 ){
                thisLi.hide();
            }
            if( resultLength !=0 && resultLength2 == 0 ){
                thisLi.show();
            }
        }else{
            thisLi.hide();
        }    
    }

 

   目標節點匹配失敗 目標節點即有父節點又有子節點:

    // 目標節點匹配失敗 目標節點即有父節點又有子節點
    function checkAllArray(arr,arr2,treeNode){
        var result = [];
        var result2 = [];
        var thisTid = treeNode.tId;
        var thisLi = $("#"+thisTid);
        var val = inputArea.val(); // 獲取檢索值
        for(var m=0;m<arr.length;m++){ // 匹配子節點或父節點
            var num = matchNode(arr[m]);
            if( num != -1 ){
                result.push(arr[m]); // 匹配成功儲存至數組
            }
        }
        var resultLength = result.length; // 獲取匹配成功后返回的數組長度
        for(var m=0;m<arr2.length;m++){ // 匹配子節點或父節點
            var num = matchNode(arr2[m]);
            if( num != -1 ){
                result2.push(arr2[m]); // 匹配成功儲存至數組
            }
        }
        var resultLength2 = result2.length; // 獲取匹配成功后返回的數組長度
        if( resultLength == 0 && resultLength2 == 0 ){ // 子節點和父節點都匹配失敗
            thisLi.hide();
        }else{ 
            thisLi.show(); // 有一種匹配成功或都匹配成功
        }
    }

  定義搜索方法:

    function searchArea(treeId, treeNode){ // 定義搜索方法
        var inputArea = $("input[name='searchArea']");
        var val = inputArea.val(); // 獲取檢索值
        var treeObj=$.fn.zTree.getZTreeObj("homeTree"); // 設置根節點
        var node = treeObj.getNodes(); // 獲取根節點
        var nodes = treeObj.transformToArray(node); // 獲取所有節點
        console.log(nodes);
        for(var i=0;i<nodes.length;i++){
            var thisNodePid = nodes[i].pId;
            var thisParentNode =  
            parentArray = [];
            childArray = [];
            getParentsNode(nodes[i]); // 獲取目標節點所有父節點 返回數組
            getChildrenNode(nodes[i]); // 獲取目標節點所有子節點 返回數組
            var num = matchNode(nodes[i]);
            if( nodes[i].isParent == false ){ 
                if( num != -1 ){
                    checkTrueArray(parentArray,nodes[i]);
                }else{
                    checkFalseArray(parentArray,nodes[i]);
                }
            }
            if( nodes[i].isParent == true ){
                if( num != -1 ){
                    checkTrueArray(parentArray,nodes[i]);  
                    checkTrueArray(childArray,nodes[i]);                  
                }else{
                    checkAllArray(parentArray,childArray,nodes[i]);
                }
            }            
        }
       
    }

  調用搜索方法:

    // 調用搜索方法
    $(".searchAreaBtn").click(function(treeId, treeNode){
        searchArea(treeId, treeNode);
    });
    var inputArea = $("input[name='searchArea']");
    inputArea.keyup(function(treeId, treeNode,e){
        var e = event || window.event;
        var val = inputArea.val();
        if( e.keyCode == 13 || val == "" ){
            searchArea(treeId, treeNode);
        }
    });

 

  看效果(電腦ps出問題了,用美圖秀秀拼的圖~囧...):

結語

  理論上來說應該是能支持無限層的,最多試了四層,沒有問題,沒有做更多測試,有興趣的看官可以試試,為了便於親們能及時獲取demo,這里附上下載鏈接,希望能對大家有所幫助,點個贊唄~
點我下載demo

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM