原理
N叉树的遍历
每个data的数据格式如下:
var oneChoice = {
name: 'A',
child: [
{
name: 'A-1'
child:[
{...},
{...}
]
},
{
}
]
}
最终拼接成的html格式如下。
<li>
<span>-</span>AAA
<ul>
<li><span>-</span>a1
<ul style="display: block;">
<li><span>-</span>a1-1</li>
<li><span>-</span>a1-2</li>
</ul>
</li>
<li><span>-</span>a2</li>
<li><span>-</span>a3
<ul style="display: block;">
<li><span>-</span>a3-1</li>
<li><span>-</span>a3-2
<ul style="display: block;">
<li><span>-</span>a3-2-1</li>
<li><span>-</span>a3-2-2</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
实际上就是一个N叉树的遍历。
那是什么遍历呢?
很显然,是一个前序遍历,遵循着“根左右”的顺序。从根开始,先将第一层第一个选项中所有的子孙选项展开,再到第一层第二个选项…
当然,也有其他的做法,例如菜单展开的时候,只希望展开第一层中的选项,而第二第三层的选项等用户点击后再进行加载。那么这种情况可以考虑使用层级遍历。
这里我按照前序遍历的方式来写,可以先来做一做这道题,做完之后自然明白该怎么写了。
/*
// Definition for a Node.
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> preorder(Node root) {
if (root == null) {
return res;
}
helper(root);
return res;
}
private void helper(Node root) {
if (root == null) {
return;
}
res.add(root.val);
for(Node oneNode: root.children){
if(oneNode != null){
helper(oneNode);
}
}
}
}
框架就可以写出来了。
// 返回对应格式的html str
function createTree(data) {
if(data为空){
return '';
}
var str = '<ul>';
for (选项 in data.child) {
str += <li> ;
str += '<span>-</span>' + 选项.name;
// 递归
if (选项.child) {
str += createTree(data[i].child);
}
str += '</li>';
};
str += '</ul>';
return str;
};
显示/隐藏功能
这个功能不难实现,只要使用display: none;和display:visible;来控制这块ul是否显示就行了。
- 如果子ul的display状态为visible,则点击将会
- 隐藏子ul
- 将-变成+
- 如果子ul的状态为none,则点击将会
- 显示子ul
- 将+变成-
//单击事件
$(".lists ul li").click(function (event) {
//判断有没有ul子级
if ($(this).find("ul").is(":visible")) {
//隐藏 +
$(this).find("ul").hide();
$(this).find("span").text("+");
} else {
//显示 -
$(this).find("ul").show();
$(this).find("span").text("-");
}
})
防止冒泡
就是在触发子类的函数时,防止父类也执行了子类中的行为。
如图,如果不阻止来自子类的冒泡事件,点击了b1-1-1-1时,就会使得BBB,乃至菜单root也会被关闭掉,这显然是不行的。
//单击事件
$(".lists ul li").click(function (event) {
event.stopPropagation(); //阻止事件冒泡
//判断有没有ul子级
if ($(this).find("ul").is(":visible")) {
//隐藏 +
$(this).find("ul").hide();
$(this).find("span").text("+");
} else {
//显示 -
$(this).find("ul").show();
$(this).find("span").text("-");
}
})
完整代码
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Page Title</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<style>
ul {
list-style-type: none;
}
ul li span {
color: red;
padding-right: 10px;
}
</style>
</head>
<body>
<div class="lists"></div>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<script>
var data = [
{
name: 'AAA',
child: [
{
name: 'a1',
child: [
{
name: 'a1-1'
}, {
name: 'a1-2'
}
]
},
{
name: 'a2'
},
{
name: 'a3',
child: [
{
name: 'a3-1'
}, {
name: 'a3-2',
child: [
{
name: 'a3-2-1'
}, {
name: 'a3-2-2'
}
]
}
]
}
]
},
{
name: 'BBB',
child: [
{
name: 'b1',
child: [
{
name: 'b1-1',
child: [
{
name: 'b1-1-1',
child: [
{
name: 'b1-1-1-1',
child: [
{
name: 'b1-1-1-1-1',
child: [
{
name: 'b1-1-1-1-1-1'
},
]
},
]
},
]
},
]
},
]
},
{
name: 'b2'
},
{
name: 'b3'
}
]
},
{
name: 'CCC',
child: [
{
name: 'c1'
}
]
},
{
name: 'DDD'
}
];
$(function () {
//递归
function createTree(data) {
var str = '<ul>';
for (var i = 0; i < data.length; i++) {
str += '<li><span>-</span>' + data[i].name;
if (data[i].child) {
str += createTree(data[i].child);
}
str += '</li>';
};
str += '</ul>';
return str;
};
$(".lists").html(createTree(data));
//单击事件
$(".lists ul li").click(function (event) {
event.stopPropagation(); //阻止事件冒泡
//判断有没有ul子级
if ($(this).find("ul").is(":visible")) {
//隐藏 +
$(this).find("ul").hide();
$(this).find("span").text("+");
} else {
//显示 -
$(this).find("ul").show();
$(this).find("span").text("-");
}
})
})
</script>
</body>
</html>