实现目标:三级目录菜单分别称为:顶级目录、次级目录、底级目录,实现对各层级目录进行选择操作时,同步影响其他目录的选择状态
具体要求:
1、当顶级目录取消选中时,次级目录和底级目录全部取消选中;
2、当有一个次级目录选中时,其顶级目录也为选中状态;
当有一个次级目录取消选中时,其底级目录全部取消选中;
当所有的次级目录都取消选中时,其顶级目录也取消选中;
3、当底级目录选中时,其次级目录和顶级目录也全部选中;
界面效果
html代码部分
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="Generator" content="EditPlus®">
<meta name="Author" content="">
<meta name="Keywords" content="">
<meta name="Description" content="">
<title>Document</title>
</head>
<style type="text/css">
.list{ width:300px; border:1px solid #ccc; margin:10px; padding:10px;}
.sec{ padding-left:20px; margin:10px;}
.last{ padding-left:20px; margin:10px;}
.submit{ text-align:center; margin:30px;}
</style>
<body>
<form name="main" action="check-all-up-post.php" method=post >
<div class="list">
<div class="title">-- 顶级目录 <br>
-- 次级目录 <br>
-- 底级目录</div>
<br>
<div class="top">
<input type="checkbox" name="T1" value="1" onClick="checkTop('1')" >
<b>系统使用</b>
<div class="sec">
<input type="checkbox" id="p3" name="S1[]" value="3" onClick="checkSec('1',this.id)" >
系统使用规范
<div class="last">
<input type="checkbox" id="p4" name="L1[]" value="4" onClick="checkLast('1',this.id)" >
添加
<input type="checkbox" id="p5" name="L1[]" value="5" onClick="checkLast('1',this.id)" >
删除
<input type="checkbox" id="p6" name="L1[]" value="6" onClick="checkLast('1',this.id)" >
编辑 </div>
</div>
<div class="sec">
<input type="checkbox" id="p7" name="S1[]" value="7" onClick="checkSec('1',this.id)" >
系统使用详情
<div class="last">
<input type="checkbox" id="p8" name="L1[]" value="8" onClick="checkLast('1',this.id)" >
添加
<input type="checkbox" id="p9" name="L1[]" value="9" onClick="checkLast('1',this.id)" >
删除
<input type="checkbox" id="p10" name="L1[]" value="10" onClick="checkLast('1',this.id)" >
编辑 </div>
</div>
</div>
<div class="top">
<input type="checkbox" name="T2" value="2" onClick="checkTop('2')" >
<b>会议资料</b>
<div class="sec">
<input type="checkbox" id="p11" name="S2[]" value="11" onClick="checkSec('2',this.id)" >
会议报告
<div class="last">
<input type="checkbox" id="p12" name="L2[]" value="12" onClick="checkLast('2',this.id)" >
添加
<input type="checkbox" id="p13" name="L2[]" value="13" onClick="checkLast('2',this.id)" >
删除
<input type="checkbox" id="p14" name="L2[]" value="14" onClick="checkLast('2',this.id)" >
编辑 </div>
</div>
</div>
<div class="submit"><input type="submit" value="确认提交" /></div>
</div>
</form>
</body>
</html>
js代码部分
<script type="text/javascript">
/* 顶级top目录选择事件
分析:
达成目标:
顶级目录取消选中时,子级目录同步取消选中;顶级目录选中时,子级目录无操作
实现思路:
1、保证sec和last目录表单的name值中的数值部分与top表单的name值数值保证一致,用以标记为同一组,可分别记做T1、S1、L1
2、根据传入的id值,获取当前top目录的表单选中状态
3、遍历所有元素,根据id值找到当前top下的所有sec和last目录表单并修改选择状态
*/
function checkTop(id){
//获取当前页面所有元素节点数
var len = document.main.elements.length;
//根据当前id值,获取当前top目录选择框的选中状态
var topchecked = document.all("T"+id).checked;
//alert(topchecked);
//遍历所有元素,根据id找出所有当前top目录下的sec和last目录
for( var i=0;i<len;i++){
if(document.main.elements[i].name == 'S'+id+'[]' || document.main.elements[i].name == 'L'+id+'[]'){
if(topchecked == false){
document.main.elements[i].checked = topchecked;
}
}
}
}
/* 次级sec目录选择事件
分析:
达成目标:
次级目录有一个选中时,顶级目录同步选中,底级目录无操作;
当所有次级目录取消选中时,顶级目录同步取消选中,同时底级目录也取消选中
实现思路:
1、对顶级目录操作。遍历所有元素,如果有1个次级目录是选择状态,则顶级目录也为选中状态,如果所有次级目录都未选中,则顶级目录也为未选中状态
2、对底级目录操作。当前次级目录如果未选中,则设置其底级目录也为未选中;如当前次级目录为选择状态,其底级目录无操作
*/
function checkSec(id,sid){
/********** 对底级目录的操作 **********/
//获取当前节点
var curNode = document.getElementById(sid);
//通过sid获取当前节点的下一个兄弟节点
var nextNode = curNode.nextElementSibling;
//获取该兄弟节点的所有子节点
var subNode = nextNode.childNodes;
//遍历所有子节点
for(var i=0;i<subNode.length;i++){
//筛选出input节点,并且上级节点状态为未选中时,设置所有子节点状态为未选中
if(subNode[i].name && curNode.checked==false){
subNode[i].checked = false;
}
}
/*********** 对顶级目录的操作 **********/
//获取当前节点
var len = document.main.elements.length;
//alert(len);
for(var i=0;i<len;i++){
//遍历元素,找出当前目录的次级目录,并进行下一步操作
if(document.main.elements[i].name == 'S'+id+'[]'){
//如果有1个次级目录是选择状态,则顶级目录也为选中状态
if(document.main.elements[i].checked){
//设置顶级目录为选中状态
document.all("T"+id).checked = true;
return;
}
}
}
//如果所有次级目录都未选中,则顶级目录也设置未选中
document.all("T"+id).checked = false;
}
/* 底级last目录选择事件
*/
function checkLast(id,sid){
/** 对次级目录的处理 **/
//获取当前节点
var curNode = document.getElementById(sid);
//通过当前节点找出上级节点的上一个兄弟节点
var brotherNode = curNode.parentNode.previousElementSibling;
//console.log(curNode.checked);
//如果当前底级目录选择状态为已选中,则设置其上级即次级目录也为选中状态
if(curNode.checked){
brotherNode.checked = true;
}
/** 对顶级目录的处理 **/
//获取当前页面所有元素节点数
var len = document.main.elements.length;
for(var i=0;i<len;i++){
//遍历元素,找出当前底级目录
if(document.main.elements[i].name == 'L'+id+'[]'){
//如果有1个底级目录是选择状态,则顶级目录也为选中状态
if(document.main.elements[i].checked){
//设置顶级目录为选中状态
document.all("T"+id).checked = true;
return;
}
}
}
}
</script>
Ps:本次实例是楼主在网上搜寻了一些js代码样例,然后在其基础上结合自己的需求逻辑进行修改的。路过的朋友如果还有更好的实现逻辑及方法,欢迎留言讨论,以求共同进步,谢谢!
在此基础上 补充另一个多选框三级联动实现方法
htmld代码:
<div class="container">
<form method="POST" action="/Menus/create">
<div class="form-group row">
<label for="controller" class="col-md-4 col-form-label text-md-right">选择权限</label>
<div class="col-md-6">
<input name="menus" type="checkbox" id="1" value="" onclick="checkTop(0,this.id,0,array<!--这里的数组需要先转成json字符串 json_encode()方法实现-->)">系统管理<br/>
<input name="menus" type="checkbox" id="2" value="" onclick="checkTop(0,this.id,1,array)">菜单添加<br/>
<input name="menus" type="checkbox" id="3" value="" onclick="checkTop(0,this.id,1,array)">系统日志<br/>
<input name="menus" type="checkbox" id="4" value="" onclick="checkTop(0,this.id,0,array)">用户管理<br/>
<input name="menus" type="checkbox" id="5" value="" onclick="checkTop(0,this.id,4,array)">用户列表<br/>
<input name="menus" type="checkbox" id="6" value="" onclick="checkTop(0,this.id,5,array)">添加
<input name="menus" type="checkbox" id="8" value="" onclick="checkTop(0,this.id,5,array)">编辑<br/>
<input name="menus" type="checkbox" id="7" value="" onclick="checkTop(0,this.id,4,array)">角色列表<br/>
<input name="menus" type="checkbox" id="9" value="" onclick="checkTop(0,this.id,7,array)">添加
<input name="menus" type="checkbox" id="10" value="" onclick="checkTop(0,this.id,7,array)">编辑<br/>
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">确认添加</button>
</div>
</div>
</form>
</div>
js代码
<script type="text/javascript">
function checkTop(i,id,pid,str){
var list1 = [];
var list2 = [];
list1 = getSubmenus(i,id,str,list1);
//console.log(list);
list2 = getSupmenus(i,pid,str,list2);
//alert(typeof(list));
//console.log(list);
var list = list1.concat(list2);
console.log(list);
//根据当前id值,获取当前顶级选择框的选中状态
var topchecked = document.getElementById(id).checked;
//alert(topchecked);
//根据获取的list子菜单数据,设置checkbox的选中状态与当前菜单选择框选择状态一致
for(var i=0;i<list1.length;i++){
//alert(list[i]);
document.getElementById(list1[i]).checked = topchecked;
}
//根据获取的list父菜单数据,设置checkbox的选中状态与当前顶级选择框选中状态一致,取消选中则不处理
for(var i=0;i<list2.length;i++){
//alert(list[i]);
if(topchecked){
document.getElementById(list2[i]).checked = topchecked;
}
}
}
//遍历检索获取当前菜单下所有子菜单
function getSubmenus(i,id,str,list1){
//alert(id);return false;
//将js对象转化为js数组
var objs = eval(str);
//console.log(objs);
//遍历数组
for(var j = 0;j<objs.length;j++){
//遍历到的pid值如果等于当前id值,则说明当前菜单找到了其子类菜单,并写入到list数组中
if(objs[j].pid == id){
//获取当前id值,用于递归时使用
var sid = objs[j].id;
list1.push(sid);
//alert(sid);
//删除当前遍历元素,防止重复遍历
//objs.splice(j,1);
getSubmenus(i,sid,objs,list1);
}
}
return list1;
}
//遍历检索获取当前菜单的所有父菜单
function getSupmenus(i,pid,str,list2) {
//alert(id);return false;
//将js对象转化为js数组
var objs = eval(str);
//console.log(objs);
//遍历数组
for(var j = 0;j<objs.length;j++){
//遍历到的pid值如果等于当前id值,则说明当前菜单找到了其子类菜单,并写入到list数组中
if(objs[j].id == pid){
//获取当前id值,用于递归时使用
var sid = objs[j].id;
list2.push(sid);
//alert(sid);
//删除当前遍历元素,防止重复遍历
//objs.splice(j,1);
getSupmenus(i,objs[j].pid,objs,list2);
}
}
return list2;
}
</script>