测试节点是否有任何匹配给定选择器的子节点的现代,简洁和快速方法是什么?
简明扼要"我的意思是类似于jQuery或功能风格,比如避免循环。我知道原生选择者越来越多地从事这类事情,但却没有跟上发展的步伐。如果浏览器中不存在这种情况,那么我也想知道。
我预计它会很简单但是搜索Google和SO会发现许多使用jQuery的错误命中或在任何深度找到任意后代而不仅仅是直接的孩子。在浏览器之间添加和标准化许多功能风格的方法之前,还有一些过时的问题。
答案 0 :(得分:5)
一种选择是使用direct child combinator, >
和:scope
pseudo-class:
var children = parentElement.querySelectorAll(':scope > div');
var parentElement = document.querySelector('.container');
var children = parentElement.querySelectorAll(':scope > div');
for (var i = 0; i < children.length; i++) {
children[i].style.background = '#f00';
}
.level2 { background-color: #fff; }
<div class="container">
<span>Span</span>
<span>Span</span>
<div class="level1">Direct 'div'
<div class="level2">Nested 'div'</div>
</div>
<div class="level1">Direct 'div'
<div class="level2">Nested 'div'</div>
</div>
<div class="level1">Direct 'div'
<div class="level2">Nested 'div'</div>
</div>
</div>
请注意,:scope
伪类仍被视为实验性的,并且没有完整的浏览器支持。但是,它可能是最“现代”的解决方案(正如您所要求的那样)。
或者,您可以使用.filter()
method并检查父元素的子元素是否与给定的选择器匹配:
function getChildren(parent, selector) {
return Array.prototype.filter.call(parent.children, function(node) {
return node.matches(selector);
});
}
用法:
getChildren(parentElement, 'div'); // Direct children 'div' elements
function getChildren(parent, selector) {
return Array.prototype.filter.call(parent.children, function(node) {
return node.matches(selector);
});
}
var parentElement = document.querySelector('.container');
var children = getChildren(parentElement, 'div');
for (var i = 0; i < children.length; i++) {
children[i].style.background = '#f00';
}
.level2 { background-color: #fff; }
<div class="container">
<span>Span</span>
<span>Span</span>
<div class="level1">Direct 'div'
<div class="level2">Nested 'div'</div>
</div>
<div class="level1">Direct 'div'
<div class="level2">Nested 'div'</div>
</div>
<div class="level1">Direct 'div'
<div class="level2">Nested 'div'</div>
</div>
</div>
答案 1 :(得分:3)
具有更广泛浏览器支持的解决方案:
[].some.call(yourEl.children, function(e){return e.matches(".z")})
在简洁性方面,在ES2015中(显然,通过使用转换器),使用箭头功能会更好:
[].some.call(yourEl.children, e=>e.matches(".z"))
使用Array.from
(ES2015):
Array.from(yourEl.children).some(e=>e.matches(".z"))
或者,实用程序功能中的 :
function childMatches(elmt, selector){
return [].some.call(elmt.children, function(e){
return e.matches(selector);
});
}
<强>用法强>
childMatches(yourElement, ".any-selector-you-want")
答案 2 :(得分:1)
使用子选择器>
document.querySelectorAll('.parent-selector > .child-selector').length > 0
答案 3 :(得分:0)
如果要从特定节点开始应用选择器但不能假设:scope
支持,则可以为此特定节点构建选择器
function selectorPath(node) {
var idx;
if (node.nodeName === 'HTML' || !node.parentNode) return node.nodeName;
idx = Array.prototype.indexOf.call(node.parentNode.children, node);
return selectorPath(node.parentNode) + ' > ' + node.nodeName + ':nth-child(' + (idx + 1) + ')';
}
然后在多部分选择器中使用它可能看起来像这样
function selectChildAll(parent, selector) {
var pSelector = selectorPath(parent) + ' > ';
selector = pSelector + selector.split(/,\s*/).join(', ' + pSelector);
return parent.querySelectorAll(selector);
}
使用它的一个示例可能是,要从此答案的内容中获取所有<p>
和<pre>
直接孩子,
var node = document.querySelector('#answer-35028023 .post-text');
selectChildAll(node, 'p, pre'); // [<p>…</p>, etc]