Ztree + PHP 无限级节点递归查找

一、前言

简单的描述一下,实习几个原理,思想,其实写很多东西,思想算是最重要的。

1、目标:将写一个无限节点的树形目录结构,如下图

澳门新浦京电子游戏 1

本文实例讲述了js
递归json树实现根据子id查父id的方法。分享给大家供大家参考,具体如下:

【干货篇】步步为营,带你轻松掌握jQuery!,轻松掌握jquery

写在前面:


 

经过系统的学习了原生JS之后,会发现其具有以下三个特点:

1、是一种解释性脚本语言(代码不进行预编译)。
2、主要用来向 HTML 页面添加交互行为。
3、可以直接嵌入 HTML 页面,但写成单独的js文件有利于结构和行为的分离。

而接下来要讲的jQuery
就对原生javascript的一个扩展,封装,就是让javascript更好用,更简单。

换而言之,jquery就是要用更少的代码,漂亮的完成更多的功能。{Write
less, Do more!
}

  1. jQuery 作为 JavaScript 的代码库,自然是使用 JavaScript 语言编写的。
  2. jQuery 的代码非常规范,执行效率也很高,是 JavaScript
    编码的优秀范例。
  3. 很多情只要使用 jQuery 的方法就可以实现大部分的 JavaScript 功能。

所以说,程序员作为一种极懒的物种存在,势必想着要减少不必要的代码劳动量,因此jQuery诞生了。

 


一、jQuery基础语法 


1、适应JQuery、必须要先导入JQuery。x.x.x.js文件。

 2、JQuery中的选择器: $(“选择器”).函数(); ①
$是JQuery的缩写形式,即也可以使用JQuery(“选择器”).函数(); ②
选择器,可以是任何CSS支持的选择符;
3、文档就绪函数:防止文档在未完全加载之前,运行JQuery代码;

 $(document).ready(function() {
 //JQuery代码
 });
 简写形式如下:
 $(function(){});

[文档就绪函数&window.onload的区别]


window.onload必须等到网页中的所有内容(包括图片视频)加载完成后才能执行代码;
文档就绪函数只需要在 网页DOM结构加载完成之后,就可以执行代码; ②
window.onload只能写一个,写多个之后只会执行最后一个;
文档就绪函数可以写多个,而且不会覆盖。 4、原生JS对象与JQuery对象: ①
使用$(“”)选中的是JQuery对象,只能调用JQuery函数,而不能使用元素的JS事件与函数;

 $("#p").click() √
 $("#p").onclick = function(){}; ×

解释:

$(“#p”)是JQuery对象,.onclick是原生的JS事件。
同理,使用document.getElement系列获取的是原生JS对象,也不能使用JQuery相关函数。
② 原生的JS对象转为 JQuery对象 可以使用$() 包裹即可以转为JQuery对象 var p
= document.getElementsByTagName(“p”); $(“p”).click(); √
原生的JS对象已经转为 JQuery对象; ③ JQuery转为原生JS对象:
使用get(index)或者[index]

 $("#p").get(0).onclick() = function () {}; √
 $("#p").[0].onclick() = function () {}; √

5、 由于其其他的库也可能使用$作为自身标识,导致其他的JS库与JQuery冲突。
① 要解决冲突,可以放弃使用$,直接使用JQuery对象。  

 !function ($) {
 $()//函数之中,就可以使用$代替JQuery对象。
 }(jQuery); 

② [jQuery.noConflict();]

运行这个函数将变量$的控制权让渡给第一个实现它的那个库
在运行这个函数后,就只能使用jQuery变量访问jQuery对象。


二、02-JQueryDOM操作及其他函数


使用$()直接创建一个标签节点

将创建好的节点,插入到指定位置。

澳门新浦京电子游戏,在#div1内部的最后,直接插入一个节点。

$("#div1").append("<p>这是被插入的p标签</p>");

把新节点插入到#div1中

$("<p>这是被插入的p标签</p>").appendTo("#div1");

在#div1内部的开头,直接插入一个节点。

$("#div1").prepend("<p>这是被插入的p标签</p>");
$("#div1").after("<p>这是被插入的p标签</p>");
$("<p>这是被插入的p标签</p>").insertBefore("#div1");

把每个p标签外面,都包裹一层div

$("p").wrap("<div></div>");

/ 把所有的p标签,包裹在同一个div中

$("p").wrapAll("<div></div>");

把#div1里面的所有子元素,用<div>包裹起来

$("#div1").wrapInner("<div></div>");

删除元素的父标签

$("#p").unwrap();

将所有匹配的p标签,全部换为span标签

$("p").replaceWith("111");

用span元素,替换掉所有p标签

$("111").replaceAll("p");

删除#div1中的所有子元素。 但是#div1依然保留空标签

$("#div1").empty();

直接从DOM中,删除#div1以及所有子元素

$("#div1").remove();

直接从DOM中,删除#div1以及所有子元素

$("#div1").detach();

重点 【remove和detach异同】 1、相同点: ①
都会把当前标签,以及当前标签的所有子节点,全部删除; ②
都可以在删除时,把当前节点返回。并可以使用变量接受返回的节点,以便后期恢复;

2、 不同点:

使用接受的节点,恢复原节点时。
remove只能恢复节点的内容,但是事件绑定,不能再恢复;
detach不但恢复节点的内容,还能再恢复 事件的绑定;   案例 ↓

$("#div1").click(function(){
alert(1);
})
var div1 = null;
$("button:eq(0)").click(function(){
div1 = $("#div1").remove();
})
$("button:eq(1)").click(function(){
div1 = $("#div1").detach();
})
$("button:eq(2)").click(function(){
$("button:eq(2)").after(div1);
});

重点 [JS中.cloneNode() 和 JQ中 .clone()区别]

两者都接受传入true/false的参数。

.cloneNode()
不传参数或传入参数false,表示只克隆当前节点,而不克隆子节点。
传入true表示可隆全部子节点。

.clone()
无论传入哪个参数,都会克隆所有子节点。但是,不传参数或者传入false,表示只克隆节点,不克隆节点绑定的事件。
传入true表示同时克隆及诶单绑定的事件。  

$("#div1").clone(true).empty().insertBefore("button:eq(0)")

CSS和属性相关操作

使用attr()设置或者取到元素的某个属性。

 

//$("#div1").attr("class","cls1");

/*$("#div1").attr({ //使用attr一次性设置多个属性
"class" : "cls1",
"name" : "name1",
"style" : "color:red;"
});*/
console.log($(".p").attr("id"));

删除元素属性
$("#div1").removeAttr("class");

prop与Attr区别。
对于checked/disabled等属性名等于属性值的属性,使用prop返回的将是true或false,
使用attr返回的将是属性名或者undefined
所以,对于属性名等于属性值,或者属性是true/false的特殊属性,通常使用prop选取。
其他的属性,通常使用attr选取。

console.log($("button:eq(2)").attr("disabled"));
console.log($("button:eq(2)").prop("disabled"));

给元素添加class属性,与attr添加class的不同是,使用addClass添加的新类名,将会保留原来已有的class名。

$("p").addClass("selected1 selected2");

删除掉元素指定的class

$("p").removeClass("selected1");

元素有指定class名,则删除; 元素没有指定class名,则新增。

$("p").toggleClass("selected1");

取到或设置元素里面的html,相当于innerHTML

console.log($("#div1").html());
$("#div1").html("<h1>我是新的h1</h1>");

取到或设置元素里面的文字内容,相当于innerText

console.log($("#div1").text());
$("#div1").text("<h1>我是新的h1</h1>");

获取或设置 元素的Value值

console.log($("input[type='text']").val());
$("input[type='text']").val("啧啧啧!");

给元素设置CSS样式属性 属于style行级样式表权限

$("#div1").css({
"color":"red",
"user-select":"none",
"text-stroke":"0.5px blue"
});

var id = setInterval(function(){
$("#div1").css({
"width":function(index,value){
if(parseFloat(value)+10 >= 600){
clearInterval(id);
}
return parseFloat(value)+10+"px";
}
});
},500);

 获取和设置元素的width和height属性

console.log($("#div1").height());
console.log($("#div1").width());
$("#div1").width("400px");

获取元素的内部宽度。 包括宽高和padding

console.log($("#div1").innerHeight());
console.log($("#div1").innerWidth());

获取元素的外部宽高。 包括宽高+padding+border

传入参数为true时,还要包括margin  

console.log($("#div1").outerHeight(true));
console.log($("#div1").outerWidth()); 

offset(): 获取元素,相对于浏览器窗口左上角的偏移位置。
这个位置,包括margin/position等。
返回的是一个对象,包含两个属性,分别是left和top

position():

获取定位元素,相对于父元素的偏移位置(父元素必须是定位元素)。
这个位置,只包括top/left等定位属性。
而margin将被视为当前元素的一部分,并不会视为偏移量范畴。  
如果父元素有定位属性。则相对于父元素padding左上角定位;
如果父元素没有定位属性,则与offerSet一样
,相对于浏览器左上角定位(但是,只是两者的定位原点都在浏览器左上角。
在计算偏移量时,offerSet会计算margin和top. 而position只计算top)。


三、JQuery 事件及动画


 

【绑定事件的方式】 1、绑定事件的快捷方式。

$("button").eq(0).click(function () {
alert("快捷绑定!");
})

缺点:绑定的事件无法取消!

2、使用on()绑定事件 : ① 使用on进行单事件绑定;

$("button:eq(0)").on ("click",(function () {
alert("这是使用on绑定的事件!");
});

② 使用on,一次性给同一个节点,添加多次事件;多个事件之间,用空格分隔!

$("button:eq(0)").on ("click dbclick",(function () {
alert("这是使用on绑定的事件!");
});

③ 使用on,同一次给一个节点添加多个事件,分别执行不同的函数。

$("button:eq(0)").on ({
"click":function () {
alert("执行了click事件!")
},
"mouseover":function () {
alert("执行了mouseover事件!")
}
});

④ 调用函数时,同时给函数传入指定参数:

$("button:eq(0)").on ("click",{name:"wq",age:23},(function (evn) {
alert(evn);
});

⑤ 使用on进行事件委派!!! 重点问题!!!  
>>>将原本需要绑定到子元素上的事件,绑定到其祖先节点乃至根节点上面,在委派给子元素节点,生效!
eg: $(“p”).on(“click”,function(){}); 事件委派 如下:

$("document").on("click","p",function(){});

>>>作用:
不使用事件委派的绑定方式,只能将事件绑定到初始化时的子元素标签上,
当页面新增同类型标签时,这些新增的标签上,没有之前绑定的事件。 而 使用
事件委派时
,当页面新增更同类型标签时,这些新增的事件也具有之同类型前标签所绑定的事件!
  3、off()取消事件绑定

$("p").off("click"):取消单事件绑定
$("p").off("click mouseover dbclick"):取消多事件绑定
$(document).off("click","p"):取消委派事件绑定
$("p").off()取消所有的事件绑定

4、使用.one()绑定的事件,只能执行一次;

eg:
$("button").one("click",function () {
alert("one做的 只能点一次!")
})

5、.trigger()自动 触发某元素事件; 第一个参数:是需要触发的事件类型;
第二个参数:(可选)数组格式,表示传递给事件函数的参数;
>>>传递进来的参数,可以在事件函数中,定义形参进行获取
(形参第一个必须是event事件,所以从第二个开始为所传递的参数!)
>>> 也可以直接在函数中,使用arguements对象数组,读取参数;  
6、.triggerHandler():功能同上,区别如下: ①
.triggerHandler()不能触发浏览器默认的HTML事件,如submit等; ②
.trigger()可以触发页面中所有匹配元素的事件;
而.triggerHandler()只能触发第一个匹配元素的事件; ③
.trigger()的返回值,返回的是调用当前函数的对象,符合JQuery的可链式语法;
.triggerHandler()返回的是事件函数的返回值,如果事件函数没有返回值,则返回的是Undefined;
 JQuery动画  1、.show()
让隐藏的元素显示,效果为同时修改元素的宽度、高度、opacity属性; ①
不传参数:直接显示,不进行动画; ② 传参:
参数为时间毫秒数,表示动画多少时间结束; ③
传入(时间,函数)表示动画完成之后,执行回调函数; .hidde()
让显示的元素隐藏,与show相反;   2、.slideDown()
让隐藏的元素显示,效果为从上往下,逐渐增加高度; .slideUp()
让显示的元素隐藏,效果为从下往上,逐渐减少高度;
.slideToggle():让显示的元素隐藏,让隐藏的元素显示;   3、.fadeIn()
让隐藏的元素淡入显示。 .fadeOut() 让显示的元素淡入隐藏。 .fadeToggle()
让隐藏的元素淡入显示,让显示的元素淡入隐藏。
.fadeTo(动画总时间,结束时透明度,函数)接受的第二个参数,表示最终达到的透明度;
  4、animate: ({最终的样式属性,键值对对象},
动画事件,动画效果(“linear”,”swing”), 动画执行完后的回调函数)
自定义动画的注意事项: ①
参数一的对象中,链必须使用驼峰法命名。{fontSzie:”18px”} ②
只有数值类型的属性可以使用动画效果。  


四、JQuery 高级  Ajax


 

台与服务器进行少量数据交换,AJAX
可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。 很多使用
AJAX 的应用程序案例:新浪微博、Google 地图、开心网、百度搜索等等。
澳门新浦京电子游戏 2    
二、AJAX是基于现有的Internet标准
AJAX是基于现有的Internet标准,并且联合使用它们:

  • XMLHttpRequest 对象 (异步的与服务器交换数据)
  • JavaScript/DOM (信息显示/交互)
  • CSS (给数据定义样式)
  • XML
    (作为转换数据的格式,现在基本上被淘汰了,大多数情况下使用JSON数据格式

  AJAX应用程序与浏览器和平台无关的! 三、AJAX的应用函数: 1、.load()
载入远程 HTML 文件代码并插入至 DOM 中。
可以只传入一个参数,表示加载一个静态的HTML代码片段。 默认使用 GET 方式 –
传递附加参数时自动转换为 POST 方式。 eg:
$(“#div1”).load(“load.html”,{参数},function () {对参数进行函数处理});  
2、$.ajax() 通过 HTTP 请求加载远程数据。jQuery 最底层 AJAX 实现函数。
接受一个大的对象。对象里面的属性和方法,表示ajax请求的相关设置: ①
url:被请求的远程文件的路径。 ② Ajax请求的类型,可选值get/post.
•success: 请求成功的回调函数。接受一个参数data,表示后台返回的数据。
•dataType:预期服务器返回的数据类型。 “json”: 返回 JSON 数据 。 “text”:
返回纯文本字符串 •data:对象格式。向后台发送一个对象,表示传递的数据。
常用于type为post的请求方式。 如果type为get,可以使用?直接追加载URL后面。
•error:请求失败时的回调函数
•statusCode:接受一个对象,对象的键值对是status状态码和对应的回调函数,
表示当请求状态码是对应数字时,执行具体的操作函数. 404 – 页面没有找到!
200 – 请求成功! 500 – 内部服务器错误! 3、 $.get(); $.post();
这两个函数,是在$.ajax()的基础上进行封装而来。可以直接默认发送get请求或post请求;
  接受四个参数: ① 请求的URL路径。 相当于$.ajax()里面的url; ②
向后台传递的数据。 相当于$.ajax()里面的data; ③ 请求成功的回调函数。
相当于$.ajax()里面的success; ④ 预期返回的数据类型。
相当于$.ajax()里面的dataType; 4、 AJax的各种监听事件:
ajaxStart—>ajaxSend—>ajaxSuccess/ajaxError/ajaxComplete—>ajaxStop

$(document).ajaxSend(function(){
alert("ajax请求发送")
});
$(document).ajaxStop(function(){
alert("ajax请求停止")
})
$(document).ajaxStart(function(){
alert("ajax请求开始")
})
$(document).ajaxSuccess(function(){
alert("ajax请求成功")
})
$(document).ajaxError(function(){
alert("ajax请求失败")
})
$(document).ajaxComplete(function(){
alert("ajax请求完成(不管成功失败,都会死乞白赖出来)")
})

 

5、 序列化表单数据的一些操作: ①、 序列化表单数据为一个字符串

$("#btn1").click(function(){
var str = $("#form1").serialize();
console.log(str);
//str = name=jianghao&password=123&email=1234123
var arr = str.split("&");
console.log(arr);
var obj = {};
for (var i=0; i<arr.length; i++) {
var arr1 = arr[i].split("=");
var keys = arr1[0];
var values = arr1[1];
obj[keys] = values;
}
console.log(obj);
$.get("01-JQuery基础.html?"+str,obj,function(){

})
})

 

2、序列化表单数据为一个数组

$("#btn2").click(function(){
var arr = $("#form1").serializeArray();
console.log(arr);
var obj = {};
for (var i=0; i<arr.length; i++) {
var keys = arr[i].name;
var values = arr[i].value;
obj[keys] = values;
}
console.log(obj);
});

3、 $.parseJSON(str) 将JSON字符串转为JSON对象
标准的JSON字符串,键必须用双引号包裹。

var str = '{"age":12}'
var obj = $.parseJSON(str);
console.log(obj);

4、 .trim() 去除掉字符串两端空格

var str1 = " 123 ";
console.log(str1.trim());

5、 用户遍历数组和对象
遍历数组时,函数的第一个参数是下标,第二个参数是值;
遍历对象时,函数的第一个参数是键,第二个参数是值

var arr = [1,2,3,4,5,6,7];
var obj = {
name : "zhangsan",
age : 12,
sex : "nan"
}
$.each(obj,function(index,item){
console.log(index);
console.log(item);
});

 


五、JQuery插件 plugin


 1、fullpage插件


1、fullpage插件简介:
澳门新浦京电子游戏 3

 

fullPage.js 是一个基于 jQuery
的插件,它能够很方便、很轻松的制作出全屏网站,主要功能有:

  • 支持鼠标滚动
  • 支持前进后退和键盘控制
  • 多个回调函数
  • 支持手机、平板触摸事件
  • 支持 CSS3 动画
  • 支持窗口缩放
  • 窗口缩放时自动调整
  • 可设置滚动宽度、背景颜色、滚动速度、循环选项、回调、文本对齐方式等等

2、引入文件 fullPage.js必须在JQuery.js文件之后导入!
澳门新浦京电子游戏 4

 

3、htm基本样式:
澳门新浦京电子游戏 5

 

在fullPage中,class为section表示一个屏幕。
section不能执行包裹在body中,必须使用一个div包裹所有的section。
section中的每一个slide表示一个横向幻灯片,可在当前屏中左右横向切换。
3、CSS样式写法无差别 4、JavaScript:
澳门新浦京电子游戏 6

 

5、属性配置: ①、选项:
 澳门新浦京电子游戏 7  
2、回调函数

① afterLoad:当一个页面加载完成之后触发
传递参数:
anchorLink:当前页面的锚链接
index:当前页面的序号,从1开始。
afterLoad:function (anchorLink,index) {
console.log(anchorLink);
console.log(index);
},
//② onLeave:当页面离开时触发的函数:
/* 接收 index、nextIndex 和 direction 3个参数:
index 是离开的“页面”的序号,从1开始计算;
nextIndex 是滚动到的“页面”的序号,从1开始计算;
direction 判断往上滚动还是往下滚动,值是 up 或 down
*/
onLeave:function (index,nextIndex,direction) {
console.log(index);
console.log(nextIndex);
console.log(direction);
},
// afterRender 页面结构生成后的回调函数,或者说页面初始化完成后的回调函数,执行一次。
// 先执行afterRender 再执行afterLoad:
afterRender:function () {
console.log("页面初始化完成了!")
},

/* afterSlideLoad:当幻灯片加载完成时执行的函数,接收四个参数
* >>>anchorLink:幻灯片所在的section的锚点
* >>>index:幻灯片所在的section的序号
* >>>slideAnchor:幻灯片自身的锚点(如果没有显示slideIdex)
* >>>slideIdex:幻灯片自身的序号
*/

afterSlideLoad:function (anchorLink,index,slideIndex,direction) {
console.log(anchorLink);
console.log(index);
console.log(slideIndex);
console.log(direction);
}

onSlideLeave 左右移动幻灯片加载之前执行的回调函数,与 onLeave 类似,
// 接收 anchorLink、index、slideIndex、direction 4个参数
/* anchorLink:幻灯片所在的section的锚点
index:幻灯片所在的section的序号
slideIndex:当前幻灯片自身的index(从0开始)
direction:幻灯片移动的方向left和right
nextSlideIndex:即将显示的幻灯片的index
*/
onSlideLeave :function function_name () {

}

 

二、move插件 1、插件简介: Move.js 提供了创建 CSS3 动画的最简单的
JavaScript API。 2、使用方法:

<script type="text/javascript" src="js/move.js"></script> 
(move插件并不是JQ插件,是原生插件,无需链接jq文件。)
<script type="text/javascript">
document.getElementById('playButton').onclick = function() {
move('.box')

.set("margin-left","300px") //设置css样式
.set("margin-top","300px")

.add("margin-left", "200px")//add()方法用来增加其已经设置的属性值。该方法必须数值型值,以便用来增加。
//该方法必须有两个参数:属性值和其增量
.sub("margin-left", "200px") //sub()是add()的逆过程,他接受两个相同的参数,但其值将从属性值中减去。
.rotate(90)//该方法通过提供的数值作为参数来旋转元素。
//当方法被调用的时候通过附加到元素的 transform 属性上。

.skew(30, 40)//skew()用于调整一个相对于x和y轴的角度。
//该方法可以被分为skewX(deg)和skewY(deg)两个方法
.scale(3, 3) //该方法用于放大或压缩元素的大小,按照提供的每一个值,将调用transform的scale方法
// .then()//用于分割动画为两个集合,并按顺序执行。动画将被分为两步,通过then()方法实现分割
.x(300) //设置X轴位置
.y(300) //设置Y轴位置 和添加margin值效果一样。

.delay(1000) //延时多少毫秒之后执行动画
.duration('5s')//设置动画的播放时间。
.end(function() {
alert("Animation Over!");
}) //end()该方法用于Move.js代码片段的结束,他标识动画的结束。
//技术上,该方法触发动画的播放。该方法接受一个可选的callback回掉函数
};
</script>

 

  三、validate插件 1、插件简介 jQuery Validate
插件为表单提供了强大的验证功能,让客户端表单验证变得更简单,同时提供了大量的定制选项,满足应用程序各种需求。该插件捆绑了一套有用的验证方法,包括
URL 和电子邮件验证,同时提供了一个用来编写用户自定义方法的
API。所有的捆绑方法默认使用英语作为错误信息,且已翻译成其他 37 种语言。
2、插件的使用:
澳门新浦京电子游戏 8

3、

澳门新浦京电子游戏 9

  4、使用示范

$(function () {
$("#commentForm").validate({
 //rules对象 用于声明各个input的验证规则;
rules:{
//选择每个input时需要先选中该input的name,并对应一个对象设置多条验证规则;
name:{
required:true,
minlength:2

},

email:{
required:true,
email:true
},
url:{

url:true,
}
},
 //messages对象 用于显示各个input验证不通过时的提示文字。
 //messages对应的各个规则都会有默认的提示,如果没有特殊需要,无需单独设置。
messages:{
name:{
required:"这个内容是必填项!",
minlength:"这里最少输入两个字符!"

},
email:{
required:"这个内容是必填项!",
email:"邮箱格式错误!"
},
url:{

url:"url格式错误!",
}
}
})
})

5、特殊用法
澳门新浦京电子游戏 10  
澳门新浦京电子游戏 11  
   

写在前面: 经过系统的学习了原生JS之后,会发现其具有以下三个特点:
1、是…

步骤:

1、你的下载 插件  ztree。然后布置在你的项目中。

<script src="__PUBLIC__/js/jquery-1.4.4.min.js"></script> 
<script src="__PUBLIC__/js/jquery.ztree.core-3.5.js"></script>

2、相关CSS

<link rel="stylesheet" href="__PUBLIC__/css/zTreeStyle/zTreeStyle.css" type="text/css"> 
<link rel="stylesheet" href="__PUBLIC__/css/zTree.css" type="text/css">

以上CSS 和JS 以你自己的为准。

3、目录结构DIV

<div class="content_wrap"  style="background:#666;"> 
    <div class="zTreeDemoBackground left"> 
        <ul id="treeDemo" class="ztree"></ul> 
    </div> 
</div> 
<div class="content-text" id="text"></div>

4、自己单独js中的代码

<SCRIPT  src="__PUBLIC__/js/ztreeonload.js"></SCRIPT>

里面写的相关功能及配置!

//配置项 
var setting = { 
     isSimpleData : true,              //数据是否采用简单 Array 格式,默认false  性   
     showLine : true,                  //是否显示节点间的连线   
     checkable : true,    
     callback: { 
         onClick: zTreeOnClick       
     } 
 }; 

 var zNodes;//数据变量 

 //ajax提交数据,请求后台PHP处理返回出目录结构json数据 
 $.ajax({ 
     url:"/admin.php/Ztree", 
     type: "get", 
     async: false, 
     dataType:"json",   
     success: function (data) { 
             //alert(data); 
             zNodes=data;    //将请求返回的数据存起来 
              //alert(zNodes); 
     }, 
     error: function (){//请求失败处理函数   
         alert('请求失败');   
     },   
 }) 

 //初始化ztree目录结构视图! 
 $(document).ready(function(){ 
     //alert("111"); 
     $.fn.zTree.init($("#treeDemo"), setting, zNodes); 
 });

5、后台PHP 递归算法,从数据库中查找目录结构并且生成 JSON数据

地址:如4中,AJAX所请求的
【/admin.php/Ztree】我这里是用的ThinkPHP框架,所以url是这个样子,以你自己的接口文件为准!

<?php 
            //父节点数组 
            $arr=array(); 
            $arr_str0 = array("name" =>'函数库查询','children'=>$this->SelectSon(1));       //父节点  Pid=1; 
            $arr_str1 = array("name" =>'数据库查询','children'=>$this->SelectSon(2));       //父节点  Pid=2; 

            array_push($arr, $arr_str0); 
            array_push($arr, $arr_str1);//这里是2个父节点。 

            echo(json_encode($arr)); //这是最后返回给页面,也就是返回给AJAX请求后所得的返回数据 JSON数据 
?> 

//这里仅仅是一个方法,一个调用SelectSon()方法,返回一个数组集合!但其中用的是递归! 
<?php 
        //查找子节点        Pid=父节点ID 
        private function SelectSon($Pid){ 

            $m=M('ztree'); 

            if(($info=$m->where("Pid='$Pid'")->select())) //查找该父ID下的子ID 
            { 
                $data=array(); 
                for ($i=0; $i < count($info) ; $i++)  
                {  
                    $da=array("name" =>$info[$i]['name'],'children'=>$this->SelectSon($info[$i]['id']));  //递归算法! 

                    array_push($data, $da);//加入子节点数组 
                }; 

                return $data;//一次性返回子节点数组,他们成为同级子节点。 
            } 
            else 
            { 
                return null; 
            } 

        } 
?>

注意:由于我是用的thinkphp框架。所以在方法调用上
有些不同,纯PHP文件中,思路应该是一样的,

首先是: 写一个数组。一个父节点的数组。

其次:  写一个方法,传递的参数是
父节点的ID,查询其子节点,在子节点中查询之后,用递归的方式继续查找子节点的子节点,直到最后查询完毕之后,返回数组给调用方法的父节点数组。然后再

echo(json_encode($arr));

转码成 JSON 将其输出,以便于AJAX异步访问,得到JSON数据。

得到之后,回到刚刚的JS功能代码中,直接初始化树目录结构,将其JSON数据传入OK。

最近做了一个类似用js实现思维导图的功能,作为思维导图,一定会有树状结构的数据产生,在操作里面的节点时会经常需要查找节点
的父节点及父节点。

总结:

其主要思想分2步走。第一步,是如何能把目录生成出来。先测试时,可以用静态数据。类似于

var node=[ 
    {name:'父节点',children:[{name:'子节点',children:null},{name:'同级子节点',children:null}]} 
] 

先分析一下,这串数据,他有什么规律。你就会发现。其实很有规律。无限节点,其实就是每个json中,有children,而且 
还有同级子节点。

你先用固定数据 生成目录结构之后

你就可以开始考虑,动态的向node传目录结构的数据了。就是我们后面所谓的
AJAX请求 PHP得到JSON数据,

PHP处理中,我用的是递归算法,返回JSON数据。及完成了。目录结构。

哦对了。

$m=M('ztree');

这句代码是thinkphp 实例化 数据操作对象的。

用来查询数据库中,节点是否存在。就是存在子节点,就返回给子节点数组,有几个就加入子节点数组中,查询完了。然后一次性返回,他们就成了同级子节点了

对于未知层级的树状数据,用for循环是无法实现的,因为不知道要循环几层,那么最合适的方法就是用js递归

"orgTreeData":{ "nodeId":"19A5B", "nodeName":"预分析用户:1313.85万人", "nodeType":"root", "expand":true, "dataCnt":13138494, "children":[ { "nodeId":"19A5B_19A5C", "nodeName":"客户状态", "nodeType":"tag", "children":[ { "nodeId":"19A5B_19A5C_19A5E", "nodeName":"包含", "dataCnt":"0人", "nodeType":"domain", "counted":2, "children":[ { "nodeId":"19A5B_19A5C_19A5E_19A67", "nodeName":"积分", "nodeType":"tag", "children":[ ], "expand":true, "counted":0, "condType":"1", "dataType":1, "propType":"1", "propSql":"", "labelId":"BLD00013", "linked":false, "linkedId":"" }, { "nodeId":"19A5B_19A5C_19A5E_19A68", "nodeName":"是否通信客户", "nodeType":"tag", "children":[ ], "expand":true, "counted":0, "condType":"3", "dataType":1, "propType":"4", "propSql":"", "labelId":"BLD00010", "linked":false, "linkedId":"" } ], "expand":true, "expressType":"7", "expressValue1":[ "17", "14" ], "expressValue2":"", "expressValue3":"17##14", "expressValue4":"实名制停机##IPBUS帐户封锁停机", "expressValue5":"实名制停机,IPBUS帐户封锁停机", "linked":false, "linkedId":"" }, { "nodeId":"19A5B_19A5C_19A60", "nodeName":"包含", "dataCnt":"0人", "nodeType":"domain", "counted":2, "children":[ { "nodeId":"19A5B_19A5C_19A60_19A69", "nodeName":"入网归属地域", "nodeType":"tag", "children":[ { "nodeId":"19A5B_19A5C_19A60_19A69_19A6A", "nodeName":"包含", "dataCnt":"", "nodeType":"domain", "counted":0, "children":[ ], "expand":true, "expressType":"7", "expressValue1":[ "477", "482" ], "expressValue2":"", "expressValue3":"477##482", "expressValue4":"鄂尔多斯##阿盟", "expressValue5":"鄂尔多斯,阿盟", "linked":false, "linkedId":"" } ], "expand":true, "counted":0, "condType":"2", "dataType":1, "propType":"3", "propSql":"1005", "labelId":"BLD00017", "linked":false, "linkedId":"" } ], "expand":true, "expressType":"7", "expressValue1":[ "40" ], "expressValue2":"", "expressValue3":"40", "expressValue4":"营业销户", "expressValue5":"营业销户", "linked":false, "linkedId":"" } ], "expand":true, "counted":0, "condType":"2", "dataType":1, "propType":"3", "propSql":"1002", "labelId":"BLD00004", "linked":false, "linkedId":"" }, { "nodeId":"19A5B_19A61", "nodeName":"全球通级别 && 全球通级别", "nodeType":"tag", "children":[ ], "expand":true, "counted":0, "condType":"2", "dataType":1, "propType":"3", "propSql":"1004", "labelId":"BLD00008", "linked":true, "linkedId":"19A5B_19A64" }, { "nodeId":"19A5B_19A62", "nodeName":"同证件号码数量", "nodeType":"tag", "children":[ ], "expand":true, "counted":0, "condType":"1", "dataType":1, "propType":"1", "propSql":"", "labelId":"BLD00009", "linked":false, "linkedId":"" } ]}

我这个对象结构是按nodeId匹配的,每个下级为children数组。

如果我想点击任何一个节点根据节点nodeId得到它的父节点nodeId,就得把整个json树递归遍历一遍,知道找到这个节点,从而得到它的父节点

关于递归,一定要掌握好结束条件,懂得何时return,不然会出现返回不出值或者循环提前结束的情况。

//传入参数:需要遍历的json,需要匹配的idfindPnodeId{ //设置结果 let result; if  { return;//如果data传空,直接返回 } for (var i = 0; i < data.children.length; i++) { let item = data.children[i]; if (item.nodeId == nodeId) { result=data.nodeId; //找到id相等的则返回父id return result; } else if (item.children && item.children.length > 0) { //如果有子集,则把子集作为参数重新执行本方法 result= findPnodeId; //关键,千万不要直接return本方法,不然即使没有返回值也会将返回return,导致最外层循环中断,直接返回undefined,要有返回值才return才对 if{ return result; } } } //如果执行循环中都没有return,则在此return return result;}

总之,递归相当于上图中的轨迹查找。

条件执行到 需要 重新执行 findPnodeId
方法的地方开始一头扎进去,如果第下一次执行找到了符合条件的值,则return出来,返回上一层,下一层的findPnodeId
方法结束,返回值,上一层的findPnodeId方法也就直接return结束了。

如果下一层方法 进入循环第一次依然没有找到 符合的值
,如果还有子集,则会继续向更下一层进发;就像上图中的红线,直到没有子集才结束,所以千万不让直接
在递归 findPnodeId 方法前直接return,也就是这样:

else if (item.children && item.children.length > 0) { return findPnodeId;}

这样会使 json在第一条树轨迹结束时如果找不到值 强制 retrun
undefined,因为没一个方法都向上return,for循环中,一旦return,会直接打断循环,使方法结束,结果是最底层
的undefined 直接return到顶层,顶层直接将undefined
return出来,根本没有走第234条线,所以一定要先判断一下是否返回值再return,像这样:

} else if (item.children && item.children.length > 0) { result= this.findPnodeId; if{ return result; }}

那么如果方法前不写return会怎样?

是方法无法return,依然无法递归

PS:关于json操作,这里再为大家推荐几款比较实用的json在线工具供大家参考使用:

在线JSON代码检验、检验、美化、格式化工具:

JSON在线格式化工具:

在线XML/JSON互相转换工具:

json代码在线格式化/美化/压缩/编辑/转换工具:

在线json压缩/转义工具:

更多关于JavaScript相关内容可查看本站专题:《JavaScript中json操作技巧总结》、《JavaScript查找算法技巧总结》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript数学运算用法总结》

希望本文所述对大家JavaScript程序设计有所帮助。

发表评论

电子邮件地址不会被公开。 必填项已用*标注