请注意:这个问题与我在这里发现的其他一些问题非常相似,但是不重复,所以请仔细阅读:
基本上我想通过(比如)类名从集合中排除节点及其所有后代。
我所做的扩展(检查代码段)在给定的示例中工作得很好,但是我愿意找到更简单/更优雅的方法(如果它当前存在于jquery中)。
然而,我正在寻找一种通用方式来执行$(this).find('<some_selector>').exclude_found_nodes_that_have_the_following_between_aforementioned_this_and_itself('<exclusion_selector>')
类似$(this).find('<exclusion_selector>:ignore_branch_if_this_node_met() <some_selector>')
之类的东西也可以完成这项工作。
ID实际上并不存在于代码中,它们纯粹是出于演示目的而添加的(“起始节点”被用户选中)。
$.fn.find_exclude = function(original_selector,exclude_selector) {
var counter=$(this).parents(exclude_selector).length;
if ($(this).is(exclude_selector)){
counter++;
}
var tmp=$(this).find(original_selector);
return tmp.filter(function(){
if($(this).is(exclude_selector) || $(this).parents(exclude_selector).length>counter){
return false;
}
return true
});
};
$(function(){
var all_b_in_main_not_in_groups=$("#main").find_exclude('b','.group');
var all_b_in_inner_not_in_groups=$("#inner").find_exclude('b','.group');
all_b_in_main_not_in_groups.each(function(){
$(this).css('color','red');
});
all_b_in_inner_not_in_groups.each(function(){
$(this).css('opacity','0.5');
});
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<span id="main">
<b>I should be red</b>
<div class="group" id="inner">
<span>
<b>I should be opaque but not red</b>
</span>
</div>
<div>
<b>I should be red</b>
<div class="group">
<b>Don't touch me, please.</b>
<div>
<b>Don't touch me, please.</b>
<p>
<b>Don't touch me, please.</b>
</p>
</div>
</div>
</div>
</span>
警告:在提议使用:not
或.not()
,或甚至使用.clone()
之前,请再次重读问题和给定的示例并检查您的解决方案确实有效 - 建议的解决方案应该同时使用#main
和#inner
作为起始节点(实际上不知道起始节点选择器 - 它们在$(this)
事件监听器中被称为click
)
答案 0 :(得分:2)
function customFind (findWhere, findWhat, ignoreWhat){
var totalIgnore = $(findWhere).find(ignoreWhat + ' ' + findWhat);
return $(findWhere).find(findWhat).not(totalIgnore);
}
使用:
var zzz= customFind(this,"b",".group");
zzz.css('text-decoration','underline');
答案 1 :(得分:1)
您可以使用以下插件版本。它使用.not()
可以接受另一个jQuery选择的事实:
$.fn.find_exclude = function(original_selector, exclude_selector) {
return $(this).find(original_selector).not(exclude_selector)
.not($(this).find(exclude_selector).find(original_selector));
}
$(function(){
var all_b_in_main_not_in_groups = $("#main").find_exclude('b','.group');
all_b_in_main_not_in_groups.css('color', 'red');
var all_b_in_inner_not_in_groups = $("#inner").find_exclude('b','.group');
all_b_in_inner_not_in_groups.css('opacity', '0.5');
});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id="main">
<b>I should be red</b>
<div class="group" id="inner">
<span>
<b>I should be opaque but not red</b>
</span>
</div>
<div>
<b>I should be red</b>
<div class="group">
<b>Don't touch me, please.</b>
<div>
<b>Don't touch me, please.</b>
<p>
<b>Don't touch me, please.</b>
</p>
</div>
</div>
</div>
</span>
&#13;
最后一个.not()
是主要部分:它排除了作为被排除父母后代的节点。如果某个节点同时满足原始选择器和排除选择器,则.not()
不会排除该节点,因此应用另一个.not()
(第一个)来处理这些情况。
与您的问题无关,但请注意,您不需要.each()
循环来应用.css()
方法调用。您可以将它直接应用于jQuery选择。
在评论中,您询问是否可以执行不需要首先匹配原始选择器的所有节点的搜索,然后删除那些应该与排除选择器一致排除的搜索。
这可以通过使用递归函数调用(深度优先搜索)执行节点搜索来实现,同时在到达必须被排除的节点时省略该递归搜索:
$.fn.find_exclude = function(original_selector, exclude_selector) {
if ($(this).length == 0) return $();
var $elems = $(this).children().not(exclude_selector);
return $elems.filter(original_selector)
.add($elems.find_exclude(original_selector, exclude_selector));
}
但请注意,DOM API在查找带有选择器的节点(参见jQuery使用的.querySelectorAll
)方面相对较快,所以这样做&#34;你自己&#34;这种替代方案带来了一些开销,最终可能比使用第一种方法时更昂贵。这取决于子树在待排除节点之下的大小。它们越大,替代递归方法表现越好的可能性越大。但我想在&#34;正常&#34;情况第一种解决方案会更快。