• 自写 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

  • 相关阅读:
    L3002 特殊堆栈
    L3007 天梯地图
    L3004 肿瘤诊断
    Linux常用笔记
    微信红包测试用例
    Ubuntu21 bluetooth connects to freebuds pro freebuds耳机Ubuntu21连接失败
    Freebuds Connnect Problem in the Windows Freebuds耳机windows10连接失败
    Ubuntu21 kernal5.13 Nvidia960M驱动安装系统安装
    Linux进程间通信
    Zeppelin返回503问题
  • 原文地址:https://www.cnblogs.com/wbsndbf/p/8341294.html
Copyright © 2020-2023  润新知