0

我正在尝试选择作为attr 以(ie ) 开头的元素input[type="submit"]的后代(非直接)的article元素,但如果它们也是该元素的后代则不会。idpost-article[id^="post-"]#custom-footer

这将返回input下面代码中的两个元素。

document.querySelectorAll('article[id^="post-"] :not(#custom-footer) input[type="submit"]')

与此相同。

document.querySelectorAll(':not(#custom-footer) input[type="submit"]')

HTML:

<article id="post-2">

    <div> <!-- multiple nested divs -->
        <div>
            <input type="submit"> <!-- match me -->
        </div>
    </div>

    <div> <!-- multiple nested divs -->
        <div>
            <div id="custom-footer">
                <input type="submit"> <!-- DO NOT match me -->
            </div>
        </div>
    </div>

</article>
4

2 回答 2

-1

When you have a selector of the form a :not(b) c, it selects elements matching c which are descendants of elements not matching b, where the latter are descendants of elements matching a.

This will tend not to be useful, because there may be multiple nodes between a and c, and only one of them needs to match :not(b) for the element to be selected. This only requires at least one ancestor of c below a to not match b - i.e. it selects c if not all ancestors above a match b - probably not what you intended.

If you only want elements which are not children of elements matching b, write a :not(b) > c to use a child selector instead of a descendant selector. This requires the parent of c to not match b.

Alternatively, if :not(b) is really meant to apply to ancestors rather than just the parent, then this is not generally possible. The selector you want would be like a c:not(b *), matching c with no ancestors below a matching b. However, the CSS specification forbids descendant selectors in :not(), so this won't work. This means you cannot use querySelectorAll to select elements with no ancestors matching b. As a workaround, you could write a helper function to test whether an element has an ancestor matching b, and then use Array.filter to exclude elements which do.

于 2019-11-05T17:59:06.873 回答
-1

好的,如果您想获取文章的子输入,但排除元素下的任何#custom-footer内容,则需要实现某种“最接近”功能。您只需向上查看父血统并检查选择器并忽略任何与您不想包含的匹配的选择器。

/* Polyfill */
if (!Element.prototype.matches) {
  Element.prototype.matches =
    Element.prototype.matchesSelector ||
    Element.prototype.mozMatchesSelector ||
    Element.prototype.msMatchesSelector ||
    Element.prototype.oMatchesSelector ||
    Element.prototype.webkitMatchesSelector ||
    function(s) {
      var matches = (this.document || this.ownerDocument).querySelectorAll(s),
        i = matches.length;
      while (--i >= 0 && matches.item(i) !== this) {}
      return i > -1;
    };
}

let childSel = 'article[id^="post-"] input[type="submit"]';
let parentSel = 'article[id^="post-"]'; /* Optional */
let excludeParentSel = '#custom-footer';
let filteredButtons = Array.from(document.querySelectorAll(childSel)).filter((b) => {
  return getClosest(b, parentSel) != null && getClosest(b, excludeParentSel) == null;
});

filteredButtons.forEach(btn => console.log(btn.className)); // Only 2

// See: https://gomakethings.com/how-to-get-the-closest-parent-element-with-a-matching-selector-using-vanilla-javascript/#browser-compatibility
function getClosest(elem, selector) {
  for (; elem && elem !== document; elem = elem.parentNode) {
    if (elem.matches(selector)) return elem;
  }
  return null;
};
<article id="post-2">
  <input type="submit" class="btn-valid-1">
  <!-- match me -->
  <br />
  <div>
    <div>
      <div>
        <div>
          <div>
            <input type="submit" class="btn-valid-2">
          </div>
        </div>
      </div>
    </div>
  </div>
  <!-- match me -->
  <div id="custom-footer">
    <input type="submit" class="btn-invalid">
    <!-- DO NOT match me -->
  </div>
</article>

于 2019-11-05T18:03:16.803 回答