最近边上班边做毕设(感觉自己马上要接到离职通知书了),好久没写原生js,遇到一个问题,前端请求返回了一个部门Json数组,大概长这样:
var json = [{
dId: 1,
level: 0,
dName: '研发中心',
pid: ''
}, {
dId: 101,
level: 1,
dName: '部门1',
pid: 1
}, {
dId: 102,
level: 1,
dName: '部门2',
pid: 1
}, {
dId: 103,
level: 1,
dName: '部门3',
pid: 1
}, {
dId: 10101,
level: 2,
dName: '小组1',
pid: 101
},{
dId: 10102,
level: 2,
dName: '小组2',
pid: 101
},{
dId: 10201,
level: 2,
dName: '小组1',
pid: 102
},{
dId: 10202,
level: 2,
dName: '小组2',
pid: 102
},{
dId: 10203,
level: 2,
dName: '小组3',
pid: 102
}];
我需要把它渲染成树结构,这他么居然困扰了我一早上(一边做项目组任务,一遍切换做毕设,强行解释成精力没办法集中),晚上回来,认真写写就出来了;
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="js/jquery-2.1.4.min.js" ></script>
<title>department</title>
</head>
<body>
<div id="Department"></div>
<script type="text/javascript">
$(function() {
$("#Department").on('click','span',function(){
alert($(this).siblings("input").val())
})
//模拟了后台返回的部门json数组
var json = [{
dId: 1,
level: 0,
dName: '中心',
pid: ''
}, {
dId: 101,
level: 1,
dName: '部门1',
pid: 1
}, {
dId: 102,
level: 1,
dName: '部门2',
pid: 1
}, {
dId: 103,
level: 1,
dName: '部门3',
pid: 1
}, {
dId: 10101,
level: 2,
dName: '小组1',
pid: 101
},{
dId: 10102,
level: 2,
dName: '小组2',
pid: 101
},{
dId: 10201,
level: 2,
dName: '小组1',
pid: 102
},{
dId: 10202,
level: 2,
dName: '小组2',
pid: 102
},{
dId: 10203,
level: 2,
dName: '小组3',
pid: 102
}];
// 注意我放了事先把 department-div 给加上了,后面写好了它的内容,直接 append 进来就好,当然也可以直接写在后面;
var html = '<div>'
+'<div class="center-part">'+json[0].dName+'</div>'
+'<input value="'+json[0].dId+'" type="hidden"/>'
+'</div>'
+'<div class="department-part">'
+'</div>';
// 先把最高权级的中心给渲染了(这里我在设计表结构的时候偷懒了,直接默认第一个为最高级了,所以这里就直接取了,注意:一个好的习惯就是先清空内容 empty() 再 append);
$("#Department").empty().append(html);
// 早上问题就出在这了,这个department是要一直循环添加的,所以得写在第一层 for 循环的外面;
var departmentHtml = '';
for(var i=1;i<json.length;i++){
// 偷懒again,直接在表结构中说明了它的级别,而且更偷懒的是,我指定了一共就三级,hahahahhahahaha
if (json[i].level ===1) {
// 这里少了div的结尾,因为还要判断是否存在子级的组,所以封尾放在后面了;
departmentHtml +='<div class="department">'
+'<span>'+json[i].dName+'</span>'
+'<input value="'+json[i].dId+'" type="hidden"/>';
// 因为可能要添加多个组,所以头尾拆开;
var groupHead = '![](img/more.svg)'
+'<div class="group-part">';
// groupHtml 放在for循环的外面,可以保证每次执行完内层循环后其内容被清空,这样就可以做下一个部门内小组的添加了;
var groupHtml = '';
for (var j= 1 ; j<json.length ; j++) {
// 判断父级(这是表机构设计,返回的json数组格式的局限,只能这么判断了)
if(json[j].pid === json[i].dId) {
groupHtml += '<div class="group">'
+'<span>'+json[j].dName+'</span>'
+'<input value="'+json[j].dId+'" type="hidden"/>'
+'</div>';
}
}
// groupHtml 不为空表示有子节点组级的存在,加上头尾,否则直接给department封尾
if (groupHtml !== '') {
groupHtml = groupHead + groupHtml + '</div>';
departmentHtml = departmentHtml + groupHtml + "</div>";
} else {
departmentHtml = departmentHtml + groupHtml + "</div>";
}
}
}
// 结束最外层的for循环,直接append到部门div中;
$(".department-part").empty().append(departmentHtml);
})
</script>
</body>
</html>
结果如下(旁边的图标是用来点击显隐组级部门用的,测试而已,没写样式,不要太在意):
你可能已经发现了,上面还有一个代码没写注释,我把它拎出来:
$("#Department").on('click','span',function(){
alert($(this).siblings("input").val())
})
这就是jquery的比较常用的事件绑定,用关键字 on(当然以前也有 bind、live、delelgate 之类的),
$(selector).on(event,childselector,data,function)
参照我的写法,可以比较清楚的理解各个参数的意思,
- event:必需项,这可以指定一个事件:‘click’,也可以指定一组事件:‘click dbclick mouseout’;
- childselector:可选;表示需要添加事件处理程序的元素,一般为selector的子元素,没填则表示事件绑定在 $(selector) 上;
- data:可选;需要传递的参数;
- function:必需项;当绑定事件发生时,需要执行的函数;
既然已经知道了这个事件绑定了,那么什么时候用它呢?个人觉得平时给dom写事件,最好都采用绑定这样比较稳妥,因为我们知道,事件绑定的好处就是像无赖般一旦定义了,就是死死地绑在指定选择器对应的dom上了,不关你是原本就存在于document中的 还是后面 append进去的,只要你满足绑定条件,事件一定会触发。
回到之前的代码,我的写法是获取我点击的部门所对应的dId(因为我后面要根据这个id发请求去获取用户列表),那么当我把这段代码写在 script 的最前面的时候,我就得采用如上写法,用事件绑定到 #Department 下的 span节点上(因为页面渲染是按照文档顺序的,这时候下面进行的 append 等操作还没被渲染,所以页面文档树中还没有这些dom,如果没采用事件绑定 事件是肯定不会生效的)。
但如果我们把这段代码写在 append的后面,也就是在确保你要绑定事件的 append 已经都结束了,页面文档树长已经渲染了这些 dom 了,那么你就可以不用采用事件绑定了 :
$("#Department").find("span").on('click',function(){
alert($(this).siblings("input").val())
})
这样也可以实现同样的功能的。
当然,个人建议是,在确认绑定事件不会影响后续操作时,能绑定的尽量去绑定吧。