有没有纯JavaScript等价于jQuery .has()的方法?

9
这个jQuery选择器中的:has在vanilla JS中等价于什么?
$('.main-container').children('.analytics:has(a)').not('#promo')

.main-container 内,我试图选择所有不带"id"为 "promo" 的包含<a>标签的 .analytics 元素。

我的尝试:

document.querySelectorAll('.main-container .analytics:not(#promo)')

这将使我接近我想要的结果,但我仍然需要过滤掉那些没有标签的.analytics父元素。

使用原生JS,最好的方法是什么?


它不是一个完全匹配,但你可以尝试使用contains方法。 - Jonathan Chaplin
循环遍历querySelectorAll的结果,只在this.getElementsByTagName('a').length> 0的情况下应用规则,怎么样? - Balázs Varga
使用类选择不是更简单的方法吗? - axdrv
4个回答

9
  1. 查询文档以使用您想要的选择器,例如:.analytics:not(#promo)
  2. 将NodeList转换为Array
  3. 使用谓词过滤数组:element => element.querySelector('your-selector')

element.querySelector('your-selector') 如果未找到子元素,则将计算为 null(假值)

通常作为函数

function has(nodeList, selector) {
  return Array.from(nodeList).filter(e => e.querySelector(selector))
}

const nodeList = document.querySelectorAll('.main-container > .analytics:not(#promo)')

has(nodeList, 'a').forEach(e => e.style.background = "red")
<div class="main-container">
  <div class="analytics">
    <a>Should be red</a>
  </div>
  <div class="analytics">
    Should not be red
  </div>
  <div id="promo" class="analytics">
    <a>Should not be red</a>
  </div>
</div>

作为 NodeList.prototype

NodeList.prototype.has = function(selector) {
  return Array.from(this).filter(e => e.querySelector(selector))
}

document
  .querySelectorAll('.main-container > .analytics:not(#promo)')
  .has('a')
  .forEach(e => e.style.background = 'red')
<div class="main-container">
  <div class="analytics">
    <a>Should be red</a>
  </div>
  <div class="analytics">
    Should not be red
  </div>
  <div id="promo" class="analytics">
    <a>Should not be red</a>
  </div>
</div>


如果没有与选择器匹配的元素,则返回null。在真实情况下使用时,它是假的,但并不完全相同。使用if(element.querySelector('your-selector') !== false)将始终为真。 - Travis J
请问您能否解释一下为什么它不能正确地处理包含已访问/未访问链接的元素?https://jsfiddle.net/1bqdjfrg/ - john c. j.
@RaphaelRafatpanah 谢谢。我原以为这是“伪类在jQuery中无法工作,但在纯JS中可以工作”的情况之一。但根据您的评论,我错了。 (?) - john c. j.

3

对于:has选择器没有相应的等效选择器,你需要使用一个初始选择器然后再用过滤器筛选。

var el = document.querySelectorAll('.main-container > .analytics:not(#promo)');
var res = [];
for (let x = 0; x < el.length; x++){
    if (el[x].querySelector('a')) res.push(el[x]);
}
//res has has the array of elements needed.

3
您可以选中<a>元素,然后获取它们的parentNodes节点:

var a = document.querySelectorAll('.main-container .analytics:not(#promo) a');
var yourElements = [];
for (var i = 0; i < a.length; i++) {
  yourElements.push(a[i].parentNode);
}

yourElements.forEach(e => e.style.background = "red");
<div class="main-container">
  <div class="analytics">
    <a>Should be red</a>
  </div>
  <div class="analytics">
    Should not be red
  </div>
  <div id="promo" class="analytics">
    <a>Schould not be red</a>
  </div>
</div>

编辑:刚刚注意到,这只有在<a>是您想要元素的直接子级时才起作用。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接