Javascript 使用 querySelectorAll 检索直接子项
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3680876/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using querySelectorAll to retrieve direct children
提问by mattsh
I am able to do this:
我能够做到这一点:
<div id="myDiv">
<div class="foo"></div>
</div>
myDiv = getElementById("myDiv");
myDiv.querySelectorAll("#myDiv > .foo");
That is, I can successfully retrieve all the direct children of the myDivelement that have class .foo.
也就是说,我可以成功检索myDiv具有 class的元素的所有直接子级.foo。
The problem is, it bothers me that I must include the #myDivin the selector, because I am running the query on the myDivelement (so it is obviously redundant).
问题是,我必须#myDiv在选择器中包含,这让我感到困扰,因为我正在myDiv元素上运行查询(因此它显然是多余的)。
I ought to be able to leave the #myDivoff, but then the selector is not legal syntax since it starts with a >.
我应该能够#myDiv关闭,但是选择器不是合法的语法,因为它以>.
Does anyone know how to write a selector which gets just the direct children of the element that the selector is running on?
有谁知道如何编写一个选择器,它只获取选择器正在运行的元素的直接子元素?
采纳答案by natevw
Good question. At the time it was asked, a universally-implemented way to do "combinator rooted queries" (as John Resig called them) did not exist.
好问题。在被问到时,还没有一种普遍实现的方式来进行“基于组合器的查询”(正如John Resig 所说的那样)。
Now the :scopepseudo-class has been introduced. It is not supportedon [pre-Chrominum] versions of Edge or IE, but has been supported by Safari for a few years already. Using that, your code could become:
现在:scope伪类已经被引入。Edge 或 IE 的 [pre-Chrominum] 版本不支持它,但 Safari 已经支持它几年了。使用它,您的代码可能会变成:
let myDiv = getElementById("myDiv");
myDiv.querySelectorAll(":scope > .foo");
Note that in some cases you can also skip .querySelectorAlland use other good old-fashioned DOM API features. For example, instead of myDiv.querySelectorAll(":scope > *")you could just write myDiv.children, for example.
请注意,在某些情况下,您还可以跳过.querySelectorAll并使用其他优秀的老式 DOM API 功能。例如,myDiv.querySelectorAll(":scope > *")您可以只写myDiv.children,例如。
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 othertools the DOM offers too.
否则,如果您还不能依靠:scope,我想不出另一种方法来处理您的情况而不添加更多自定义过滤器逻辑(例如 find myDiv.getElementsByClassName("foo")who .parentNode === myDiv),如果您试图支持一个真正的代码路径,显然这并不理想只想将任意选择器字符串作为输入,将匹配列表作为输出!但是,如果像我一样,你最终问这个问题只是因为你陷入了思考“你只有一把锤子”的想法,不要忘记DOM 还提供了各种其他工具。
回答by lazd
Does anyone know how to write a selector which gets just the direct children of the element that the selector is running on?
有谁知道如何编写一个选择器,它只获取选择器正在运行的元素的直接子元素?
The correct way to write a selector that is "rooted" to the current element is to use :scope.
编写“根植”到当前元素的选择器的正确方法是使用:scope.
var myDiv = getElementById("myDiv");
var fooEls = myDiv.querySelectorAll(":scope > .foo");
However,browser support is limitedand you'll need a shim if you want to use it. I built scopedQuerySelectorShimfor this purpose.
但是,浏览器支持是有限的,如果你想使用它,你需要一个垫片。我为此目的构建了scopedQuerySelectorShim。
回答by csuwldcat
Here's a flexible method, written in vanilla JS, that allows you to run a CSS selector query over only the direct children of an element:
这是一个用 vanilla 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;
}
回答by Randy Hall
if you know for sure the element is unique (such as your case with the ID):
如果您确定该元素是唯一的(例如您使用 ID 的情况):
myDiv.parentElement.querySelectorAll("#myDiv > .foo");
For a more "global" solution: (use a matchesSelector shim)
对于更“全局”的解决方案:(使用matchesSelector shim)
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;
}
where elmis your parent element, and selis your selector. Could totally be used as a prototype as well.
哪里elm是你的父元素,sel是你的选择器。也可以完全用作原型。
回答by Melle
The following solution is different to the ones proposed so far, and works for me.
以下解决方案与目前提出的解决方案不同,对我有用。
The rationale is that you select all matching children first, and then filter out the ones which are not direct children. A child is a direct child if it does not have a matching parent with the same selector.
基本原理是您首先选择所有匹配的孩子,然后过滤掉那些不是直接孩子的孩子。如果孩子没有具有相同选择器的匹配父级,则它是直接子级。
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!
哼!
回答by cpi
I created a function to handle this situation, thought I would share it.
我创建了一个函数来处理这种情况,以为我会分享它。
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;
}
In essence what you are doing is generating a random-string (randomString function here is an imported npm module, but you can make your own.) then using that random string to guarantee that you get the element you are expecting in the selector. Then you are free to use the >after that.
本质上,您正在做的是生成一个随机字符串(这里的 randomString 函数是一个导入的 npm 模块,但您可以自己制作。)然后使用该随机字符串来保证您在选择器中获得您期望的元素。然后你可以自由使用>之后。
The reason I am not using the id attribute is that the id attribute may already be used and I don't want to override that.
我不使用 id 属性的原因是 id 属性可能已经被使用,我不想覆盖它。
回答by Dustin Poissant
Well we can easily get all the direct children of an element using childNodesand we can select ancestors with a specific class with querySelectorAll, so it's not hard to imagine we could create a new function that gets both and compares the two.
好吧,我们可以使用 轻松获取元素的所有直接子元素,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;
}
Note: This will return an Array of Nodes, not a NodeList.
注意:这将返回一个节点数组,而不是一个 NodeList。
Usage
用法
document.getElementById("myDiv").queryDirectChildren(".foo");
回答by Vasile Alexandru Pe?te
I would like to add that you can extend the compatibility of :scopeby just assigning a temporary attribute to the current node.
我想补充一点,您可以通过为当前节点分配一个临时属性来扩展:scope的兼容性。
let node = [...];
let result;
node.setAttribute("foo", "");
result = window.document.querySelectorAll("[foo] > .bar");
// And, of course, you can also use other combinators.
result = window.document.querySelectorAll("[foo] + .bar");
result = window.document.querySelectorAll("[foo] ~ .bar");
node.removeAttribute("foo");
回答by Lee Chase
I'd have gone with
我会去的
var myFoo = document.querySelectorAll("#myDiv > .foo");
var myDiv = myFoo.parentNode;
回答by Greeso
I am just doing this without even trying it. Would this work?
我只是这样做,甚至没有尝试。这行得通吗?
myDiv = getElementById("myDiv");
myDiv.querySelectorAll(this.id + " > .foo");
Give it a try, maybe it works maybe not. Apolovies, but I am not on a computer now to try it (responding from my iPhone).
试一试,也许行得通,也许行不通。Apolovies,但我现在不在电脑上尝试它(从我的 iPhone 响应)。

