定义一颗树,JS中常见的树形数据结构如下,children属性对应的是子树
let tree = [
{
id: '1',
name: '节点1',
children: [
{
id: '1-1',
name: '节点1-1'
}
]
},
{
id: '2',
name: '节点2',
children: [
{
id: '2-1',
name: '节点2-1'
},
{
id: '2-2',
name: '节点2-2',
children: [
{
id: '2-2-1',
name: '节点2-2-1'
}
]
}
]
},
{
id: '3',
name: '节点3'
}
]
二、深度优先遍历(DFS)
1、递归实现
function treeIterator(tree, func) {
tree.forEach((node) =>{
func(node)
node.children &&treeIterator(node.children, func)
})
}
实现逻辑简述:定义treeIterator函数,传入tree(树)和func(回调函数)两个参数,遍历tree数组,执行回调函数,如果当前节点存在children,则递归调用。
函数调用验证:调用treeIterator函数,传入上文定义好的树结构数组,打印出每个节点的name值。
treeIterator(tree, (node) =>{
console.log(node.name)
})
控制台打印结果如下:
2、循环实现
function treeIterator(tree, func) {
let node, curTree = [...tree]
while ((node = curTree.shift())) {
func(node)
node.children &&curTree.unshift(...node.children)
}
}
实现逻辑简述:
(1)定义node作为当前节点,curTree为传入的树(不影响原数组tree);
(2)执行while循环,curTree数组第一个元素从其中删除,并返回第一个元素赋值给node;
(3)①执行回调函数;②如果当前节点存在子树,则追加到curTree数组的开头,继续执行循环,直到curTree没有元素为止。
函数调用验证:参考上述递归实现验证,方式和结果一致。
三、广度优先遍历(BFS)
function treeIterator(tree, func) {
let node, curTree = [...tree]
while ((node = curTree.shift())) {
func(node)
node.children &&curTree.push(...node.children)
}
}
实现逻辑简述:和上述深度优先遍历的循环实现差不多。区别在于如果当前节点存在子树,则追加到list数组的末尾。
JsTree是一个基于JQuery的框架,实现简单,功能比较齐全。项目中急于修改树控件,现学现卖,实现了简单的功能,仅包含异步加载,动态设置节点样式图标,靠着自己看帮助文档,多次尝试一步步完成。1. 实现异步加载
$("#tvBox").tree({
data : {
async : true,
type : "xml_flat",
[color=red]opts : {
url : URL
}
},
types : {
"default" : {
renameable : false,
deletable : false,
creatable : false,
draggable : false
}
},
ui:{
theme_name : "classic"
},
callback : {
beforedata : function(NODE, TREE_OBJ) {
setParams(NODE, TREE_OBJ)// 获取参数信息
//向服务器传递参数
return { type : type_id, dyj : dyj_id, bdz : bdz_id, jg : jg_id, ept : ept_id }
},//end beforedata
onselect : function(NODE, TREE_OBJ) { // 单击函数,点击设备节点名称的时候在右边显示信息
setParams(NODE, TREE_OBJ)// 获取参数信息
var ids = $(NODE).attr("id").split("-")
// alert(ids[6])
var subType = ids[1]
var dydj = ids[2]
//alert(type_id+" -- "+ept_id)
var nodeParam="type="+type_id+"&subType="+subType+"&bdz="+bdz_id+"&dydj="+dydj+"&ept="+ept_id
if (type_id == EptType.dyj) {//点击的是电业局节点
var dyj_url = "pages/omds/ept/dyj/dyj.jsp?dyj="+dyj_id+"&"+nodeParam
//alert(dyj_url+" -- "+dyj_name)
top.doCreateTabItem(dyj_url,
dyj_name,
dyj_url+"&random="+Math.random(),
dyj_name)//在'主页'标签中显示
}
}, //end onselect
// 只在树第一次加载的时候调用
onload : function(TREE_OBJ) {
$("#tvBox ul li a:first-child ins").hide()//电业局节点不显示图标
}
}// end callback
})// end tree()
JsTree支持多种格式的数据源,这里使用了xml格式,其实json格式更好。data中代码即可实现异步加载,通过设置UI参数可以修改主题,callback参数可以对一些事件作出响应,如beforedata可以在发送异步请求之前添加url参数,onselect可以响应生成的树中节点的单击事件,还有open在节点被打开的时候被调用,等等,可以帮助实现很多功能……
--1 碰到比较麻烦的事情是展开子节点向后台传递参数时需要用到父节点的id等信息,需要用到parent函数。
--2 另外,当展开一个节点从后台没有查询到子节点时需要返回<root></root>,不能使<root>,我当时用jdom生成xml碰到后者,出现了问题。
--3 callback中的事件需要自己去尝试才能知道什么时候被触发
2. 实现节点换肤
项目中涉及到得是电业局--变电站--间隔--设备,对于后三者节点图标必须与其状态对应,且状态是动态的,所以需要后台在生成xml的时候设置icon属性
页面既然得到从服务器传过来的json数据之后,还要转换为Object比如,服务器组装好的json数据:
{
id:'001',
nodeMsg:'节点1'
}
这个是ajax成功之后的回调
function(xhr){
var o = eval('(' + xhr.responseText + ')')
alert(o.id + ':' + o.nodeMsg)
}