唠叨一哈

  前两天朋友跟我说要一个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的可以留言,互相学习,一起进步,么么哒~

zTree搜索的更多相关文章

  1. 自写 zTree搜索功能 -- 关键字查询 -- 递归无限层

    唠叨一哈 前两天朋友跟我说要一个ztree的搜索功能,我劈头就是一巴掌:这种方法难道无数前辈还做少了?自己去找,我很忙~然后我默默地蹲着写zTree的搜索方法去了.为什么呢?因为我说了句“找不到是不可 ...

  2. jquery zTree搜索高亮的例子

    思路: 搜索的时候发请求到后台,后台根据关键字找到匹配的节点,并将这些节点添加一个标志light: 后面就根据这个light为true就高亮,false就不高亮: 后台将这些节点返回到前台,前台展示: ...

  3. ztree搜索节点并展开

    web <div class="zTreeC"> <div class="searchL" lay-filter="searchL& ...

  4. Yii目录树扩展ztree,ctree等

    ztree: http://blog.csdn.net/jake451/article/details/7091449 http://hi.baidu.com/qiangtan/item/e85c48 ...

  5. Ztree的初步使用--checkbox--指定目录下搜索子节点

    这里记录一下zTree的check的使用 首先 <%@ Page Language="C#" AutoEventWireup="true" CodeBeh ...

  6. jquery zTree异步搜索的例子--搜全部节点

    参考博客: https://segmentfault.com/a/1190000004657854 https://blog.csdn.net/houpengfei111/article/detail ...

  7. jquery zTree异步搜索的例子--搜叶子节点

    参考博客:https://www.cnblogs.com/henuyuxiang/p/6677397.html 前台代码 <%@ page language="java" c ...

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

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

  9. jquery ztree异步搜索

    一.初始异步加载树 初始化默认给出一个根结点,再结合异步加载的方式手动触发默认加载第一层,如图: 代码如下: var treeSetting = { async: { enable: true, ur ...

随机推荐

  1. Oil Skimming HDU - 4185(匹配板题)

    Oil Skimming Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tota ...

  2. 【刷题】BZOJ 1023 [SHOI2008]cactus仙人掌图

    Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的 ...

  3. 【刷题】BZOJ 4977 [Lydsy1708月赛]跳伞求生

    Description 小Q最近沉迷于<跳伞求生>游戏.他组建了一支由n名玩家(包括他自己)组成的战队,编号依次为1到n.这个游 戏中,每局游戏开始时,所有玩家都会从飞机上跳伞,选择一个目 ...

  4. 浅谈范德蒙德(Vandermonde)方阵的逆矩阵的求法以及快速傅里叶变换(FFT)中IDFT的原理

    浅谈范德蒙德(Vandermonde)方阵的逆矩阵与拉格朗日(Lagrange)插值的关系以及快速傅里叶变换(FFT)中IDFT的原理 标签: 行列式 矩阵 线性代数 FFT 拉格朗日插值 只要稍微看 ...

  5. spring data jpa查询部分字段、多余附加字段

    spring data jpa查询部分字段 第一种方法:使用 model 查询时转化 首先建立一个 model ,写上自己想要查询的字段,然后写上构造函数,这步很重要,因为spring jpa 转化时 ...

  6. POJ 2387 Til the Cows Come Home (图论,最短路径)

    POJ 2387 Til the Cows Come Home (图论,最短路径) Description Bessie is out in the field and wants to get ba ...

  7. SQL Server优化的方法

    SQL Server优化的方法<一>   查询速度慢的原因很多,常见如下几种:   1.没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷)   2.I/O吞吐量小,形成了 ...

  8. java基础基础总结----- 构造方法,可变参数列表

    package com.mon11.day2; /** * 类说明 :构造方法,可变参数列表 * @author 作者 : chenyanlong * @version 创建时间:2017年11月2日 ...

  9. 多线程(模拟买票)-----java基础知识总结

    这次的的问题引入的比较深入,如果看了这篇博客,不看下一篇,你会很懵逼. 代码: package com.day13.math; /** * 类说明 :模拟三个窗口同时售票 * @author 作者 : ...

  10. python的内置模块random随机模块方法详解以及使用案例(五位数随机验证码的实现)

    1.random(self): Get the next random number in the range [0.0, 1.0) 取0到1直接的随机浮点数 import random print( ...