如果div包含所有指定的元素,请选择它

时间:2016-01-16 11:03:04

标签: javascript jquery html jquery-selectors

我试图选择包含.itemtagOne tagTwo元素的span div。

我的div结构如下:

<div id="items">

    <div id="block1" class="item">
        <span class="tagOne tag">One</span>
        <span class="tagTwo tag">Two</span>
    </div>

    <div id="block2" class="item">
        <span class="tagOne tag">Java</span>
    </div>

</div>

使用以下jQuery,我可以分别找到标签(及其父div&#39; s)。

var blocks =  $('#items .item');

blocks.filter('.item').find('[class*="tagOne"]').parent();
blocks.filter('.item').find('[class*="tagTwo"]').parent();

然而,一旦我尝试将它们组合起来缩小到div 包含它们的那个,我就没有结果,我似乎无法解决问题为什么!

blocks.filter('.item').find('[class*="tagOne"][class*="tagTwo"]');

我的理解是逗号语法将创建一个OR表达式,而不创建AND表达式。我在AND表达式之后,因为我只想返回包含所有条件的div,或者根本没有。

注意:我这样做是因为我根据标签创建了一个切换过滤器,标准(即tagOne, tagTwo)是由标签选择的标签的串联用户(未显示)因此最好尝试在一次操作中完成。

编辑:将重复的id移至class名称,以使其有效并相应地调整JavaScript代码。

4 个答案:

答案 0 :(得分:4)

首先, ID应该是唯一的。现在,标记包含ID为tagOne的两个元素,这是无效的标记。

您可以使用class而不是ID。

  1. 选择两者中的任何一个元素(在这种情况下为.tagOne.tagTwo
  2. 使用siblings()选择具有其他类
  3. 的兄弟元素
  4. 使用closest()选择与选择器匹配的最近祖先。
  5. 上述第1步,第2步和第3步将仅选择同时包含.item.tagOne的{​​{1}}元素作为后代。

    <强>代码:

    .tagTwo

    $('.tagOne') // Select one of the element
      .siblings('.tagTwo') // Get second element if it is sibling
      .closest('.item') // Get the closest ancestor
    
    $('.tagOne') // Select one of the element
      .siblings('.tagTwo') // Get second element if it is sibling
      .closest('.item') // Get the closest ancestor
      .addClass('selected'); // For Demo purpose
    .item {
      color: red;
    }
    div.selected {
      color: green;
    }

    您也可以使用<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="items"> <div id="block1" class="item"> <span class="tagOne tag">One</span> <span class="tagTwo tag">Two</span> </div> <div id="block2" class="item"> <span class="tagOne tag">Java</span> </div> <div id="block3" class="item"> <span class="tagTwo tag">I Love JavaScript</span> </div> </div>,如下所示。

    1. 使用filter()
    2. 对所有filter元素进行迭代
    3. 使用context selector检查当前.item是否具有后代.item.tagOne
    4. 在jQuery对象上使用length属性来获取选择器选择的元素数。
    5. <强>代码:

      .tagTwo

      $('.item').filter(function() {
        return $('.tagOne', this).length && $('.tagTwo', this).length;
      })
      
      // Fiddle: https://jsfiddle.net/tusharj/8tuu1wxs/1/
      
      // Iterate over all elements having item class
      $('.item').filter(function() {
        return $('.tagOne', this).length && $('.tagTwo', this).length;
      }).addClass('selected');
      .item {
        color: red;
      }
      .selected {
        color: green;
      }

      如果元素的顺序/顺序是固定的,可以使用CSS general sibling selector ~adjacent sibling selector +

      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      <div id="items">
      
        <div id="block1" class="item">
          <span class="tagOne tag">One</span>
          <span class="tagTwo tag">Two</span>
        </div>
      
        <div id="block2" class="item">
          <span class="tagOne tag">Java</span>
        </div>
      
        <div id="block3" class="item">
          <span class="tagTwo tag">I Love JavaScript</span>
        </div>
      
      </div>

      OR

      $('.tag1 ~ .tag2').closest('.item')
      

      $('.tag1 + .tag2').closest('.item')
      
      // Fiddle: https://jsfiddle.net/tusharj/amdoLfou/1/
      
      $('.tag1 ~ .tag2') // + can also be used instead of ~
        .closest('.item') // Get closest ancestor
        .css('color', 'blue'); // For Demo purpose

答案 1 :(得分:1)

虽然您已经接受了答案,但我觉得这是一个值得简单的JavaScript的问题,而不仅仅是一个jQuery解决方案。因此,考虑到这一点,我想提供以下方法(它确实使用了一些ECMAScript 6,因此需要一个相当现代的浏览器):

// using an Immediately-Invoked Function Expression syntax,
// so that the enclosed function will be executed when
// encountered, rather than requiring the user to call it
// explicitly (this would need to run in a DOMReady callback
// or once the DOM has been constructed, however):
(function hasAll(opts) {

  // setting the default settings for the function:
  var settings = {
    // a CSS Selector string to identify the ancestor
    // element that you wish to identify:
    'ancestorSelector': 'div',

    // an array of CSS Selectors to identify the
    // descendants by which the ancestor should
    // be found:
    'descendantSelectors': []
  }

  // looking at the named (not inherited) properties
  // of the opts Object supplied by the user:
  for (var property in opts) {

    // if the opts Object has a given property
    // name we set the corresponding property
    // of the settings Object to be equal to that
    // property-value:
    if (opts.hasOwnProperty(property)) {
      settings[property] = opts[property];
    }
  }

  // finding all the elements represented by the first selector
  // of the user-supplied selectors contained within an element
  // matching the ancestor selector:
  var firstElements = document.querySelectorAll(
      settings.ancestorSelector + ' ' + settings.descendantSelectors[0]
    ),

  // converting the NodeList returned by document.querySelectorAll()
  // into an Array, using Array.from:
    arrayOfFirsts = Array.from(firstElements),

  // here we iterate over that Array, using Array.prototype.filter():
    hasSiblings = arrayOfFirsts.filter(function(n) {

      // we look for the parentNode of the current node (n):
      var p = n.parentNode;

      // we use Array.prototype.every() to ensure that every
      // selector in the descendantSelectors Array returns
      // a Node (document.querySelector() returns only the
      // first node matching the given selector, or null if
      // there is no element matching that selector).
      // if Array.prototype.every() returns true (all elements
      // of the Array match the supplied test) then the current
      // node (n) is retained in the array returned by
      // Array.prototype.filter():
      return settings.descendantSelectors.every(function(selector) {

        // Array.prototype.every() returns a Boolean,
        // true : if all elements of the Array match
        //        the supplied test/assessment,
        // false: if *any* of the elements of the Array
        //        fail to match.
        // this is the test that we're matching against:
        return p.querySelector(selector) !== null;
      });
    });

  // here we iterate over the hasSiblings Array, and use
  // Array.prototype.map() to form a new Array, using
  // an Arrow function to take the current node (n)
  // and find, and return, the closest element to that
  // node which matches the supplied settings.ancestorSelector:
  var found = hasSiblings.map(n => n.closest(settings.ancestorSelector));

  // returning that array to the calling context:
  return found;

})({
  // this is the 'opts' Object that we're passing to the
  // IIFE-contained function:
  'ancestorSelector': '.item',
  'descendantSelectors': ['.tagOne', '[data-demo]']

// using Array.prototype.forEach() to iterate over the
// returned elements, to add the class 'hasAll' to the
// the classList (the list of class-names) of the given
// node (n):
}).forEach(n => n.classList.add('hasAll'));

&#13;
&#13;
(function hasAll(opts) {
  var settings = {
    'ancestorSelector': 'div',
    'descendantSelectors': []
  }

  for (var property in opts) {
    if (opts.hasOwnProperty(property)) {
      settings[property] = opts[property];
    }
  }

  var firstElements = document.querySelectorAll(
      settings.ancestorSelector + ' ' + settings.descendantSelectors[0]
    ),
    arrayOfFirsts = Array.from(firstElements),
    hasSiblings = arrayOfFirsts.filter(function(n) {
      var p = n.parentNode;
      return settings.descendantSelectors.every(function(selector) {
        return p.querySelector(selector) !== null;
      });
    });
  var found = Array.from( hasSiblings.map(n => n.closest(settings.ancestorSelector)) );
  return found;

})({
  'ancestorSelector': '.item',
  'descendantSelectors': ['.tagOne ~ .tagTwo']
}).forEach(n => n.classList.add('hasAll'));
&#13;
div {
  width: 50%;
  margin: 0.5em auto;
  border: 2px solid #000;
  border-radius: 1em;
  padding: 0.5em;
  box-sizing: border-box;
}

.hasAll {
  border-color: #f90;
}

.hasAll span {
  color: #f90;
  font-weight: bold;
}
&#13;
<div id="items">

  <div id="block1" class="item">
    <span class="tag tagOne">One</span>
    <span class="tag tagTwo">Two</span>
  </div>

  <div id="block2" class="item">
    <span class="tag tagOne">Java</span>
  </div>

  <div id="block3" class="item">
    <span class="tag tagOne" data-demo="false">tag-one</span>
    <span class="tag tagTwo">tag-two</span>
    <span class="tag" data-demo="true">tag-three</span>
  </div>

</div>
&#13;
&#13;
&#13;

JS Fiddle demo

请注意,使用上述函数,如果祖先元素的任何后代或其后代&#39;兄弟姐妹,匹配多个选择器。

参考文献:

答案 2 :(得分:0)

试试这个

 blocks.filter('.item').find('[id="tagOne"],[id="tagTwo"]');

答案 3 :(得分:0)

尝试使用has jquery has selector搜索所选节点是否有某些子节点: https://jsfiddle.net/96gbf7xg/