有没有一种简单的方法在JQuery中的两个节点集之间执行减法?

时间:2016-10-16 09:51:21

标签: javascript jquery

请注意:这个问题与我在这里发现的其他一些问题非常相似,但是不重复,所以请仔细阅读:

基本上我想通过(比如)类名从集合中排除节点及其所有后代。

我所做的扩展(检查代码段)在给定的示例中工作得很好,但是我愿意找到更简单/更优雅的方法(如果它当前存在于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

2 个答案:

答案 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选择的事实:

&#13;
&#13;
$.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;
&#13;
&#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;情况第一种解决方案会更快。