唠叨一哈

  前两天朋友跟我说要一个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

自写 zTree搜索功能 -- 关键字查询 -- 递归无限层的更多相关文章

  1. zTree搜索

    自写 zTree搜索功能 -- 关键字查询 -- 递归无限层 唠叨一哈 前两天朋友跟我说要一个ztree的搜索功能,我劈头就是一巴掌:这种方法难道无数前辈还做少了?自己去找,我很忙~然后我默默地蹲着写 ...

  2. zTree分批异步加载方式下实现节点搜索功能(转载)

    原文地址:https://segmentfault.com/a/1190000004657854 最近公司做一个项目用到zTree,zTree功能强大就不用多说了,相信用过的人都知道.       公 ...

  3. 使用AJAX做关键字查询:输入框变化自动搜索、无刷新页面;

    使用AJAX做关键字查询要求:1.无刷新页面2.输入框变化自动搜索 <style type="text/css"> .k{ width:150px; height:30 ...

  4. JQuery :contains选择器,可做搜索功能,搜索包含关键字的dom

    假设有一个加油站列表,找到所有包含某某关键字的加油站. 选择所有包含 "is" 的 <p> 元素: $("p:contains(is)") 搜索功能 ...

  5. 尝试用React写几个通用组件 - 带搜索功能的下拉列表,开关切换按钮,弹出框

    尝试用React写几个通用组件 - 带搜索功能的下拉列表,开关切换按钮,弹出框 近期正在逐步摸索学习React的用法,尝试着写几个通用型的组件,整体项目还是根据webpack+react+css-me ...

  6. Java操作Excel(读、写、搜索关键字、插入图片)

    import java.io.File; import java.io.IOException; import jxl.Cell; import jxl.Sheet; import jxl.Workb ...

  7. 【Lucene3.6.2入门系列】第03节_简述Lucene中常见的搜索功能

    package com.jadyer.lucene; import java.io.File; import java.io.IOException; import java.text.SimpleD ...

  8. phpcms的验证码替换 及 phpcms实现全站搜索功能

    在使用phpcms替换网页的时候,除了正常的替换栏目.内容页等,其他的什么验证码啦,提交表单了,搜索功能了,这些在替换的时候可能会对一些默认文件有一些小小 的改变 下面就是自己在失败中成功的过程,最后 ...

  9. T-SQL动态查询(2)——关键字查询

    接上文:T-SQL动态查询(1)--简介 前言: 在开发功能的过程中,我们常常会遇到类似以下情景:应用程序有一个查询功能,允许用户在很多查询条件中选择所需条件.这个也是本系列的关注点. 但是有时候你也 ...

随机推荐

  1. Servlet与Jsp的结合使用实现信息管理系统一

    PS:1:先介绍一下什么是Servlet? Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,主要功能在于交互式地 ...

  2. 基于telegraf+influxdb+grafana进行postgresql数据库监控

    前言 随着公司postgresql数据库被广泛应用,尤其是最近多个项目在做性能测试的时候都是基于postgresql的数据库,为了确定性能瓶颈是否会出现在数据库中,数据库监控也被我推上了日程.在网上找 ...

  3. 系统内置委托:Func/Action

    lSystem.Func 代表有返回类型的委托 lpublic delegate TResult  Func<out TResult>(); lpublic delegate TResul ...

  4. js获取手机屏幕宽度、高度

    网页可见区域宽:document.body.clientWidth 网页可见区域高:document.body.clientHeight 网页可见区域宽:document.body.offsetWid ...

  5. 伽罗瓦域(有限域)GFq^12上元素的1→2→4→12塔式扩张(2)------第二次扩张

    接上文https://www.cnblogs.com/heshuchao/p/8196307.html 继续探讨塔式扩张的第二部分,即1→2→4→12中2 → 4的元素扩张表示方式与计算公式推导. 3 ...

  6. JSP EL隐含对象

    JSP 内置对象 JSP EL隐含对象 描述 page pageScope page 作用域 request requestScope request 作用域 session sessionScope ...

  7. 客户端 未登录页面 (clearfix 分割线)

    做了一个手机客户端页面,未登录的状态页面 类似 如上图所示 这样 上面列表采取80%宽度,右侧浮动.ul li设置绝对定位.左边icon图标采取决定定位. 为了防止小屏幕手机左边空白缝隙过小,事先给外 ...

  8. 编码(ACSII unicod UTF-8)、QT输出中文乱码深入分析

    总结: 1. qt输出中文乱码原因分析 qt的编程环境默认是utf-8编码格式(关于编码见下文知识要点一): cout << "中文" << endl; 程 ...

  9. 小子给大家分享一个或者多个新手创建tableview经常会遇到的坑(动态创建控件,xib的重用)

    小子最近做了一个根据接口返回的数据在Cell中动态创建控件,感觉应该会一部分人卡在这里,小子就跟大家分享一下: 1.控件重复创建:这个问题出现的原因是动态创建的cell内容的时候,无法进行重用设置,所 ...

  10. python3之面向对象

    1.面向对象术语 类(Class): 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例. 类属性(类变量):类属性在整个实例化的对象中是公用的.类属 ...