我可以这样做:

<div id="myDiv">
   <div class="foo"></div>
</div>
myDiv = getElementById("myDiv");
myDiv.querySelectorAll("#myDiv > .foo");

也就是说,我可以成功地检索myDiv元素的所有具有类.foo的直接子元素。

问题是,它困扰我,我必须包括在选择器中的#myDiv,因为我是在myDiv元素上运行查询(所以它显然是多余的)。

我应该能够离开#myDiv关闭,但选择器是不合法的语法,因为它以>开始。

有人知道如何编写一个选择器,它只获取选择器所运行的元素的直接子元素吗?


当前回答

我们可以很容易地使用childNodes获取元素的所有直接子元素,也可以使用querySelectorAll选择特定类的祖先元素,因此不难想象,我们可以创建一个新函数来获取两者并比较两者。

HTMLElement.prototype.queryDirectChildren = function(selector){
  var direct = [].slice.call(this.directNodes || []); // Cast to Array
  var queried = [].slice.call(this.querySelectorAll(selector) || []); // Cast to Array
  var both = [];
  // I choose to loop through the direct children because it is guaranteed to be smaller
  for(var i=0; i<direct.length; i++){
    if(queried.indexOf(direct[i])){
      both.push(direct[i]);
    }
  }
  return both;
}

注意:这将返回一个节点数组,而不是一个节点列表。

使用

 document.getElementById("myDiv").queryDirectChildren(".foo");

其他回答

function siblings(el) {
    return el.closest('*:not(:scope)').querySelectorAll(':scope > *');
}

纯JS代码

El -是元素 这里我们有一个函数,它在以下步骤中工作:

取任何直接父类,但不取我们传递的el(最接近的可以取el,因此我们确保el不会作为结果) 带走所有直系子女

我用这个:

你可以避免键入“myDiv”两次并使用箭头。 当然,总是有更多的可能性。 可能需要一个现代的浏览器。


<!-- Sample Code -->

<div id="myDiv">
    <div class="foo">foo 1</div>
    <div class="foo">foo 2
        <div class="bar">bar</div>
    </div>
    <div class="foo">foo 3</div>
</div>

// Return HTMLCollection (Matches 3 Elements)

var allMyChildren = document.querySelector("#myDiv").children;

// Return NodeList (Matches 7 Nodes)

var allMyChildren = document.querySelector("#myDiv").childNodes;

// Match All Children With Class Of Foo (Matches 3 Elements)

var myFooChildren = document.querySelector("#myDiv").querySelectorAll(".foo");

// Match Second Child With Class Of Foo (Matches 1 Element)

var mySecondChild = document.querySelector("#myDiv").querySelectorAll(".foo")[1];

// Match All Children With Class Of Bar (Matches 1 Element)

var myBarChild = document.querySelector("#myDiv").querySelector(".bar");

// Match All Elements In "myDiv" (Matches 4 Elements)

var myDescendants = document.querySelector("#myDiv").querySelectorAll("*");

下面是一个用普通JS编写的灵活方法,它允许你只对元素的直接子元素运行CSS选择器查询:

var count = 0;
function queryChildren(element, selector) {
  var id = element.id,
      guid = element.id = id || 'query_children_' + count++,
      attr = '#' + guid + ' > ',
      selector = attr + (selector + '').replace(',', ',' + attr, 'g');
  var result = element.parentNode.querySelectorAll(selector);
  if (!id) element.removeAttribute('id');
  return result;
}

好问题。在被问到这个问题的时候,普遍实现的“组合根查询”(John Resig这样称呼它们)的方法还不存在。

现在引入了:scope伪类。它不支持[pre- chromium]版本的Edge或IE,但Safari已经支持了几年。使用它,你的代码可以变成:

let myDiv = getElementById("myDiv");
myDiv.querySelectorAll(":scope > .foo");

请注意,在某些情况下,您也可以跳过. queryselectorall,并使用其他老式的DOM API特性。例如,不是myDiv。querySelectorAll(":scope > *")你可以只写myDiv。比如孩子。

Otherwise if you can't yet rely on :scope, I can't think of another way to handle your situation without adding more custom filter logic (e.g. find myDiv.getElementsByClassName("foo") whose .parentNode === myDiv), and obviously not ideal if you're trying to support one code path that really just wants to take an arbitrary selector string as input and a list of matches as output! But if like me you ended up asking this question simply because you got stuck thinking "all you had was a hammer" don't forget there are a variety of other tools the DOM offers too.

有人知道如何编写一个选择器,它只获取选择器所运行的元素的直接子元素吗?

编写“根”到当前元素的选择器的正确方法是使用:scope。

var myDiv = getElementById("myDiv");
var fooEls = myDiv.querySelectorAll(":scope > .foo");

然而,浏览器支持有限,如果你想使用它,你需要一个垫片。为此,我构建了scopedQuerySelectorShim。