考虑以下HTML片段:这基本上是一组嵌套的复选框,使用无序列表标记来创建一般分组。代码是动态生成的,因此我可以根据需要完全控制标记。
表示以下问题的jsfiddle位于:http://jsfiddle.net/bwh4rj3h/
我正在尝试创建执行以下操作的jQuery:
好的,所以我有一些适用于下面标记的jQuery代码。它工作正常。但它很难看。而且我讨厌丑陋,觉得我的逻辑,选择器和/或HTML标记存在缺陷,导致事情变得丑陋,并且有更好的方式。
很想得到一些关于更好的方式的反馈。在我个人的情况下,我不必担心超过2级,但一般的N级深层功能不应该太难。事实上,如果不是第三个条件,我正在检查“孩子们”的状态,看看是否所有东西都被检查/取消,那就相对简单了。事实上,我正在进行3次循环(因为评估顺序)让我感到难过。
提前感谢您的协助。 :)
你会注意到我正在使用:禁用检查。在我的最后一个项目中,我设置了一些禁用的复选框,因此它们不受上面列出的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);
}
});
}
});
答案 0 :(得分:2)
我已经使用不同的解决方案分叉并更新了您的JSFiddle。我对标记进行了一些更改,我认为这会更容易处理,但jQuery仍然很长。希望这会有所帮助。
Here is the updated JSFiddle。我已经对JS进行了评论,以解释它是如何工作的。
对于您的加价 - 我认为将<ul>
直接嵌套在另一个<ul>
中而不将其包含在<li>
中是不错的做法(请参阅此stack overflow question更多信息。另外,如果你完全控制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完全在小提琴中,我不会发布它以帮助简化这一点。
希望这有帮助。
干杯
答案 1 :(得分:1)
我在尝试实施同样的事情时偶然发现了你的问题。
以下是我解决问题的方法: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