对双向级联复选框使用jQuery
Using jQuery for bidirectional cascading checkboxes
考虑以下HTML片段:这基本上是一组嵌套的复选框,使用无序列表标记创建一个通用分组。代码是动态生成的,因此我可以根据需要完全控制标记。
代表以下问题的jsfiddle位于:http://jsfiddle.net/bwh4rj3h/
我正在尝试创建执行以下操作的jQuery:
- 单击"全选"可切换代码段中所有复选框的状态
- 单击矩阵中较深的复选框将切换所有"子复选框"。例如,点击Group1复选框将切换组下面的结构中所有复选框的状态
- 如果在给定的组中取消选中任何复选框,那么也必须取消选中组复选框(虽然从技术上讲,代表"部分"填充的三态复选框会很好,但这超出了我的问题范围)。例如,假设项目1-1、1-2和1-3都已检查。然后应选中组1,在本例中还应选中"全选"。然而,如果我取消选择项目1-2,现在组1不是"完整的",因此应该取消选中,"全选"也是如此
好的,我有一些jQuery代码可以用于下面的标记。它运行良好。但它很丑陋。我讨厌丑陋,觉得我的逻辑、选择器和/或HTML标记中有一个缺陷,导致事情变得如此丑陋,而且还有更好的方法。
我很想得到一些关于更好的方法的反馈。就我个人而言,我不必担心超过2级的深度,但通用的N级深度功能应该不会太难。事实上,如果不是第三种情况,即我检查"孩子"的状态,看看是否所有东西都被检查/未检查,这将相对简单。事实上,我正在做一个3次循环(因为评估的顺序)让我很难过。
感谢您的协助。:)
您会注意到我使用的是:disabled check。在我的最后一个项目中,我将一些复选框设置为禁用,因此它们对我上面列出的3个要求"免疫"。由于标记不包括任何禁用的项,因此这不应影响结果。
<ul>
<li>
<input type="checkbox" id="chkAll" checked/><label for="chkAll">Select All</label>
</li>
<ul>
<li>
<input type="checkbox" id="chkGroup1" checked/><label for="chkGroup1">Group 1</label>
</li>
<ul>
<li>
<input type="checkbox" id="chkGp1-Item1" checked/><label for="chkGp1-Item1">Item 1</label>
</li>
<li>
<input type="checkbox" id="chkGp1-Item2" checked/><label for="chkGp1-Item2">Item 2</label>
</li>
</ul>
</ul>
</ul>
jQuery:
$("input[type=checkbox]:not(:disabled)").on("change", function () {
$(this).parent().next("ul").find("li input[type=checkbox]:not(:disabled)").prop("checked", $(this).prop("checked"));
// Looping 3 times to cover all sublevels. THERE HAS GOT TO BE A BETTER WAY THAN THIS.
for (var i = 0; i < 3; i++) {
$("input[type=checkbox]:not(:disabled)").each(function() {
var uncheckedkidcount = $(this).parent().next("ul").find("li input[type=checkbox]:not(:disabled):not(:checked)").length;
var kidcount = $(this).parent().next("ul").find("li input[type=checkbox]:not(:disabled)").length;
if (kidcount > 0) {
$(this).prop("checked", uncheckedkidcount == 0);
}
});
}
});
我已经用不同的解决方案分叉并更新了您的JSFiddle。我对标记做了一些更改,我认为这些更改会使处理更容易,但jQuery仍然很长。希望这能有所帮助。
这是更新后的JSFiddle。我已经评论了JS来解释它是如何工作的。
对于您的标记,我认为将<ul>
直接嵌套在另一个<ul>
中而不将其封装在<li>
中不是一个好的做法(有关更多信息,请参阅此堆栈溢出问题)。此外,如果您可以完全控制DOM结构,我会添加一些类名以使jQuery更易于管理:
<ul>
<li>
<input type="checkbox" id="chkAll" checked/>
<label for="chkAll">Select All</label>
</li>
<li class="has-nested-list">
<ul class="nested">
<li>
<input type="checkbox" id="chkGroup1" checked/>
<label for="chkGroup1">Group 1</label>
</li>
<li class="has-nested-list">
<ul class="nested">
<li>
<input type="checkbox" id="chkGp1-Item1" checked/>
<label for="chkGp1-Item1">Item 1</label>
</li>
<li>
<input type="checkbox" id="chkGp1-Item2" checked/>
<label for="chkGp1-Item2">Item 2</label>
</li>
</ul>
</li>
</ul>
</li>
</ul>
当有嵌套列表时,为了使其在没有多个项目符号的情况下工作,我们可以添加这个简单的CSS规则
.has-nested-list {
list-style-type: none;
}
jQuery完全在小提琴里,我不会发布它来帮助使它更简短。
希望这能有所帮助。
干杯
我在尝试实现相同的东西时偶然发现了您的问题。
以下是我解决问题的方法:https://codepen.io/nexx/pen/VyLLPM.
它支持多层嵌套复选框,并遵循问题中提到的逻辑。希望它能帮助那些在同样的事情上挣扎的人。作为一个初学者,我很想听到反馈:)
<ul class="categories-list">
<li class="category"><input type="checkbox"><label>Parent category</label>
<a class='collapse-category' href=''>expand</a>
<ul class="subcategories">
<li class="category"><input type="checkbox"><label>Child category </label></li>
<li class="category"><input type="checkbox"><label>Child category </label></li>
<li class="category"><input type="checkbox"><label>Child category </label></li>
<li class="category"><input type="checkbox"><label>Child category </label></li>
<li class="category"><input type="checkbox">
<label>Child category with children</label>
<a class='collapse-category' href=''>expand</a>
<ul class="subcategories">
<li class="category"><input type="checkbox"><label>Child category </label></li>
<li class="category"><input type="checkbox"><label>Child category </label></li>
<li class="category"><input type="checkbox"><label>Child category </label></li>
<li class="category"><input type="checkbox"><label>Child category </label></li>
<li class="category"><input type="checkbox">
<label>Child category with children</label>
<a class='collapse-category' href=''>expand</a>
<ul class="subcategories">
<li class="category"><input type="checkbox"><label>Child category </label></li>
<li class="category"><input type="checkbox"><label>Child category </label></li>
<li class="category"><input type="checkbox"><label>Child category </label></li>
<li class="category"><input type="checkbox"><label>Child category </label></li>
<li class="category"><input type="checkbox"><label>Child category </label></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
jQuery
$.fn.checkboxParent = function() {
//get parent checkbox element
var checkboxParent = $(this)
.parent("li")
.parent("ul")
.parent("li")
.find('> input[type="checkbox"]');
return checkboxParent;
};
$.fn.checkboxChildren = function() {
//get checkbox children
var checkboxChildren = $(this)
.parent("li")
.find(' > .subcategories > li > input[type="checkbox"]');
return checkboxChildren;
};
$.fn.cascadeUp = function() {
var checkboxParent = $(this).checkboxParent();
if ($(this).prop("checked")) {
if (checkboxParent.length) {
//check if all children of the parent are selected - if yes, select the parent
//these will be the siblings of the element which we clicked on
var children = $(checkboxParent).checkboxChildren();
var booleanChildren = $.map(children, function(child, i) {
return $(child).prop("checked");
});
//check if all children are checked
function and(a, b) {
return a && b;
}
var allChecked = booleanChildren.reduce(and, true);
if (allChecked) {
$(checkboxParent).prop("checked", true);
$(checkboxParent).cascadeUp();
}
}
} else {
if (checkboxParent.length) {
//if parent is checked, becomes unchecked
$(checkboxParent).prop("checked", false);
$(checkboxParent).cascadeUp();
}
}
};
$.fn.cascadeDown = function() {
var checkboxChildren = $(this).checkboxChildren();
if ($(this).prop("checked")) {
if (checkboxChildren.length) {
//all children are checked
checkboxChildren.prop("checked", true);
checkboxChildren.each(function(index) {
$(this).cascadeDown();
});
}
} else {
if (checkboxChildren.length) {
//children become unchecked
checkboxChildren.prop("checked", false);
checkboxChildren.each(function(index) {
$(this).cascadeDown();
});
}
}
};
$("input[type=checkbox]:not(:disabled)").on("change", function() {
$(this).cascadeUp();
$(this).cascadeDown();
});
$(".category a").on("click", function(e) {
e.preventDefault();
$(this)
.parent()
.find("> .subcategories")
.slideToggle(function() {
if ($(this).is(":visible")) $(this).css("display", "flex");
});
});
css(sass):
.categories-list
margin: 40px 0px
padding: 0px 10px
width: 300px
.category
font-size: 14px
display: flex
flex-direction: column
position: relative
padding: 3px 0px 3px 22px
border-bottom: 1px solid #f5f5f5
font-weight: 300
display: flex
label
width: 100%
a
color: #95939a
position: absolute
right: 0px
z-index: 1000
input[type="checkbox"]
margin: 0px 10px 0px 0px
position: absolute
left: 0px
top: 7px
.subcategories
margin-left: 0px
display: none
padding: 5px
flex-direction: column
.category
padding-left: 22px
flex-direction: column
&:last-child
border-bottom: none
- jQuery复选框被锁定为选中状态
- Jquery复选框val数组
- jQuery复选框(在ul>li下)检查事件
- 使用 JQuery 复选框筛选项目列表
- jquery复选框仅在第一次加载时触发
- jQuery复选框未选中检测问题
- Jquery复选框更改事件未激发
- jQuery复选框和span共享一个单击事件
- jquery复选框树是否支持“;展开直到节点“;或“;扩展父母”;当程序地调用“;检查”;
- 显示 jQuery 复选框选择
- 没有表单的 jQuery 复选框验证
- 带有选项框架和WordPress的JQuery复选框
- jQuery - 复选框数据发布到 php
- jQuery复选框组选中/取消选中仅工作一次
- Jquery 复选框不起作用
- Jquery复选框分组 - 单击至少一个子复选框时取消选中父项,选中所有子复选框时选中父项
- 来自 HTML AJAX 响应的 jQuery 复选框控件
- jQuery复选框选中 单击按钮时切换
- Jquery 复选框筛选 - 修复
- Jquery复选框问题