使用querySelectorAll来检索直接的孩子

我能够做到这一点:

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

也就是说,我可以成功检索具有class .foomyDiv元素的所有直接子元素。

问题是,我不得不在select器中包含#myDiv ,因为我在myDiv元素上运行查询(所以显然是多余的)。

我应该能够closures#myDiv ,但是select器不是合法的语法,因为它以>开头。

有谁知道如何编写一个select器,它只是select器运行的元素的直接子元素?

好问题,但是正如你所看到的那样, John Resig给他们命名的时候没有办法做“组合根源查询”。

但是,在某些情况下,您可以跳过.querySelectorAll并使用其他良好的老式DOM APIfunction。 例如,不用不支持的myDiv.querySelectorAll("> *")你可以写myDiv.children

不幸的是,我不能想办法处理你的情况,而不添加更多的自定义filter逻辑(例如,find其.parentNode === myDiv )的myDiv.getElementsByClassName("foo") ,如果你想支持,显然不理想一个代码path,真的只是想把一个任意的select器string作为input和匹配列表作为输出! 但是如果像我这样的话,最终只是因为思考“所有的东西都是一把锤子”而提出这个问题,不要忘了DOM还提供了其他各种工具。

有谁知道如何编写一个select器,它只是select器运行的元素的直接子元素?

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

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

但是, 浏览器支持是有限的 ,如果你想使用它,你将需要一个垫片。 我为此构build了scopedQuerySelectorShim 。

注意 :: :scope伪类已被弃用。 但是,它仍然在querySelector / querySelectorAll受支持。

这里有一个灵活的方法,用vanilla JS编写,它允许你只在一个元素的直接子元素上运行一个CSSselect器查询:

 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; } 

如果你确定这个元素是唯一的(例如你的ID):

 myDiv.parentElement.querySelectorAll("#myDiv > .foo"); 

对于更“全球化”的解决scheme:(使用matchesSelector填充 )

 function getDirectChildren(elm, sel){ var ret = [], i = 0, l = elm.childNodes.length; for (var i; i < l; ++i){ if (elm.childNodes[i].matchesSelector(sel)){ ret.push(elm.childNodes[i]); } } return ret; } 

elm是你的父元素, sel是你的select器。 完全可以用作原型。

我创build了一个函数来处理这种情况,以为我会分享它。

 getDirectDecendent(elem, selector, all){ const tempID = randomString(10) //use your randomString function here. elem.dataset.tempid = tempID; let returnObj; if(all) returnObj = elem.parentElement.querySelectorAll(`[data-tempid="${tempID}"] > ${selector}`); else returnObj = elem.parentElement.querySelector(`[data-tempid="${tempID}"] > ${selector}`); elem.dataset.tempid = ''; return returnObj; } 

实质上,你正在做的是生成一个随机string(randomString函数,这里是一个导入的npm模块,但是你可以自己创build),然后使用这个随机string来保证你在select器中获得期望的元素。 那么你可以自由使用>之后。

我不使用id属性的原因是id属性可能已经被使用,我不想重写。

那么我们可以很容易地使用childNodes获取一个元素的所有直接子元素,并且我们可以使用querySelectorAllselect具有特定类的祖先,所以我们不难想象我们可以创build一个新的函数来获取并比较这两个元素。

 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; } 

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

用法

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

以下解决scheme与迄今为止提出的解决scheme不同,并且适用于我。

理由是你首先select所有匹配的孩子,然后过滤掉那些不是直接孩子的孩子。 一个孩子是一个直接的孩子,如果它没有一个匹配的父母与同一个select器。

 function queryDirectChildren(parent, selector) { const nodes = parent.querySelectorAll(selector); const filteredNodes = [].slice.call(nodes).filter(n => n.parentNode.closest(selector) === parent.closest(selector) ); return filteredNodes; } 

HTH!

我只是这样做,甚至没有尝试。 这会工作吗?

 myDiv = getElementById("myDiv"); myDiv.querySelectorAll(this.id + " > .foo"); 

试一试,也许它的作品可能不是。 Apolovies,但我现在不在电脑上试试(从我的iPhone响应)。

我已经走了

 var myFoo = document.querySelectorAll("#myDiv > .foo"); var myDiv = myFoo.parentNode;