定义一颗树,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数组的末尾。
其实很简单,就是在你if (document.getElementById('node' + no).style.display == 'none') {
document.getElementById('node' + no).style.display = 'block'}// 如果此层是隐藏的
这段里面在加一句所有子层隐藏就可以了
if (document.getElementById('node' + no).style.display == 'none') {
(要加在这里哦~要是加在document.getElementById('node' + no).style.display = 'block'这句下面就永远不会有子项显示)
document.getElementById('node' + no).style.display = 'block'}
public object ListMenu(DataTable _list){
StringBuilder sb = new StringBuilder()
DataRow[] rows = _list.Select("PID=0")
sb.Append("[")
bool isFist = false
foreach (DataRow dr in rows)
{
if (isFist)
sb.Append(",")
isFist = true
string id = dr["ID"].ToString()
sb.Append("{")
sb.AppendFormat("\"id\":\"{0}\",", dr["ID"])
sb.AppendFormat("\"text\":\"{0}\",", dr["Name"])
sb.AppendFormat("\"pid\":\"{0}\",", dr["PID"])
string submenu = GetSubMenu(id, _list)
if (submenu == "")
{
sb.AppendFormat("\"leaf\":\"{0}\",", "true")
sb.Append("\"children\":[")
}
else
{
sb.AppendFormat("\"expanded\":\"{0}\",", "true")
sb.Append("\"children\":[")
sb.Append(submenu)
}
sb.Append("]")
sb.Append("}")
}
sb.Append("]")
_menu = sb.ToString()
return _menu
}
private string GetSubMenu(string pid, DataTable dt)
{
StringBuilder sb = new StringBuilder()
DataRow[] rows = dt.Select("PID=" + pid)
if (rows.Length >0)
{
bool isFist = false
foreach (DataRow dr in rows)
{
if (isFist)
sb.Append(",")
isFist = true
string id = dr["ID"].ToString()
sb.Append("{")
sb.AppendFormat("\"id\":\"{0}\",", dr["ID"])
sb.AppendFormat("\"text\":\"{0}\",", dr["Name"])
sb.AppendFormat("\"pid\":\"{0}\",", dr["PID"])
string submenu = GetSubMenu(id,dt)
if (submenu == "")
{
sb.AppendFormat("\"leaf\":\"{0}\",", "true")
sb.Append("\"children\":[")
}
else
{
sb.AppendFormat("\"expanded\":\"{0}\",", "true")
sb.Append("\"children\":[")
sb.Append(submenu)
}
sb.Append("]")
sb.Append("}")
}
}
return sb.ToString()
}
可根据实际情况修改相应的值:如children可能是nodes