概述
问题描述
这里的多级选择组件问题,指的是存在一个多级的选择组件,当点击某个节点时,该节点及其下的所有节点都要选中,若该节点并列的所有兄弟节点都已选中,则其父节点也要勾选,依此到最顶端节点。反选也类似逻辑。
这个问题也符合平日的认知习惯。如下图所示:
如点
新华区
,则其下所有街道都要选中,再点击桥西区
,桥西区
下的街道要选中,同时石家庄市
这个节点要选中。若再点击廊坊市
这个节点,则整个河北省
都应该选中。
解决方法
有一个问题是,我们并不知道这个选择组件有多少级。如上示例为3级,但实际中是不确定的。
从问题来看,设置目标节点(点击的节点)及其下的节点的选择状态比较容易办到,如使用jquery
查询其下的所有子节点即可。比较困难的是,怎样设置父节点的状态(是否选中)?
可以想象的是,查询兄弟节点的状态,若兄弟节点有没有选中的,任务就结束了(直接返回),若兄弟节点都选中,说明其父节点也应该需要选中,好,设置父节点选中,这样还要判断父节点的兄弟节点…….这样一直循环到顶端节点。这就是所谓的递归的套路。那有没有简单的方法呢?
利用冒泡的解决方法
有一个解决的方法。原理和上面提到的类似,不过向上递归的过程我们用冒泡实现。
这种方法有一定的限制条件,首先我们把每个节点都添加一个相同的样式(有同一个class
),父节点需要包含子节点(即点击子节点时事件需能冒泡上传到父节点)。好了,这样我们只需处理一层父节点即可。
处理父节点时,若其兄弟节点有未选中的,阻止冒泡事件即可。
实践
如上面的示例,解决方法实现如下:
页面
<!DOCTYPE html>
<html>
<head>
<title>多级选择组件</title>
<style>
.one-level {
margin-left: 30px;
}
</style>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>
</head>
<body>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" value="" />河北省</label>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" value="" />石家庄市</label>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />新华区</label>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />A街道</label>
</div>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />B街道</label>
</div>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />C街道</label>
</div>
</div>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />桥西区</label>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />1街道</label>
</div>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />2街道</label>
</div>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />3街道</label>
</div>
</div>
</div>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />廊坊市</label>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />广阳区</label>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />A街道</label>
</div>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />B街道</label>
</div>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />C街道</label>
</div>
</div>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />开发区</label>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />A街道</label>
</div>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />B街道</label>
</div>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />C街道</label>
</div>
</div>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />安次区</label>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />A街道</label>
</div>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />B街道</label>
</div>
<div class="node one-level">
<button type="">选择</button>
<label><input type="checkbox" />C街道</label>
</div>
</div>
</div>
</div>
</body>
</html>
js核心实现
$('.node').on('click', function() {
// 判断事件源,只响应按钮单击事件
var tagName = event.target.tagName;
if(tagName!=='BUTTON'){
return false;
}
var name = $(this).children('label').text();
console.log('name:' + name);
var self = $(this).children('label').find('input')[0];
var children = $(this).children('.node').find('input');
if (self.checked) { //已选择,取消选择
self.checked = false;
var isAll = true;
for (let i = 0; i < children.length; i++) {
if (!children[i].checked) {
isAll = false;
break;
}
}
if (isAll) {
for (let i = 0; i < children.length; i++) {
children[i].checked = false;
}
}
} else { //未选择,勾选
self.checked = true;
for (let i = 0; i < children.length; i++) {
children[i].checked = true;
}
}
var sibs = $(this).siblings().children('label').find('input');
var isfull = true;
//查看兄弟节点,看其是否有未选中的
for (var i = 0; i < sibs.length; i++) {
if (!sibs[i].checked) {
isfull = false;
break;
}
}
if (!isfull) {
event.stopPropagation(); // 阻止事件冒泡
}
});
说明:
- 这样做会使单击事件的区域变为块状(区域为div),所以需要在开头判断事件源。
- 对于取消选中,需要判断:若是子节点有未选中的,则不需要管子节点,只需把自身取消选中即可。
- 本文未对中间态(选中、未选中、半选中)做处理,有兴趣的你可以试试
最后
以上就是香蕉高跟鞋为你收集整理的多级选择组件解决实践的全部内容,希望文章能够帮你解决多级选择组件解决实践所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复