找到具有特定类的最近的祖先元素

rvi*_*hne 194 html javascript dom

如何在纯JavaScript中找到最接近具有特定类的树的元素的祖先?例如,在这样的树中:

<div class="far ancestor">
    <div class="near ancestor">
        <p>Where am I?</p>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

然后我想要,div.near.ancestor如果我尝试这个p并搜索ancestor.

the*_*472 292

更新:现在大多数主流浏览器都支持

document.querySelector("p").closest(".near.ancestor")
Run Code Online (Sandbox Code Playgroud)

请注意,这可以匹配选择器,而不仅仅是类

https://developer.mozilla.org/en-US/docs/Web/API/Element.closest


对于不支持closest()但有matches()一个可以构建类似于@ rvighne的类匹配的选择器匹配的旧版浏览器:

function findAncestor (el, sel) {
    while ((el = el.parentElement) && !((el.matches || el.matchesSelector).call(el,sel)));
    return el;
}
Run Code Online (Sandbox Code Playgroud)

  • 2016年6月:看起来所有的浏览器仍然没有赶上 (7认同)
  • 有一个[DOM Level 4](https://github.com/WebReflection/dom4)polyfill与`nearest`以及更多高级DOM遍历功能.您可以单独提取该实现,也可以包含整个包,以便在代码中获得许多新功能. (3认同)
  • 当前版本的 Internet Explorer、Edge 和 Opera Mini 仍不支持。 (2认同)
  • @kleinfreund - IE、Edge 或 Opera mini 仍然不支持。http://caniuse.com/#search=closest (2认同)
  • 2017年2月,IE和Edge仍然没有支持lol. (2认同)
  • Edge 15具有支持,应该涵盖所有主要的浏览器。除非您计算IE11,否则不会收到任何更新 (2认同)

rvi*_*hne 187

这样做的诀窍:

function findAncestor (el, cls) {
    while ((el = el.parentElement) && !el.classList.contains(cls));
    return el;
}
Run Code Online (Sandbox Code Playgroud)

while循环等待,直到el具有所需的类,并将其设置elel所以在最后,你必须与类或祖先的父母每次迭代null.

如果有人想改进它,这是一个小提琴.它不适用于旧浏览器(即IE); 请参阅classList的兼容性表.parentElement这里使用的是因为parentNode需要更多的工作来确保节点是一个元素.

  • 如果你想在参数元素本身中检查类名,在搜索它的祖先之前,你可以简单地在循环中切换条件的顺序:`while(!el.classList.contains(cls)&&(el = el .parentElement));` (3认同)
  • 呃,我以为它不存在,[但我错了](https://developer.mozilla.org/en-US/docs/Web/API/Node.parentElement).无论如何,`parentElement`是一个相当新的属性(DOM级别4),并且`parentNode`从......永远存在.所以`parentNode`也适用于旧浏览器,而`parentElement`可能不适用.当然你可以为`classList`制作相同的参数,但它没有一个简单的替代方法,比如`parentElement`.我实际上想知道为什么`parentElement`存在,它似乎没有在`parentNode`上添加任何值. (2认同)

sim*_*bro 28

使用element.closest()

https://developer.mozilla.org/en-US/docs/Web/API/Element/closest

看到这个例子DOM:

<article>
  <div id="div-01">Here is div-01
    <div id="div-02">Here is div-02
      <div id="div-03">Here is div-03</div>
    </div>
  </div>
</article>
Run Code Online (Sandbox Code Playgroud)

这是你如何使用element.closest:

var el = document.getElementById('div-03');

var r1 = el.closest("#div-02");  
// returns the element with the id=div-02

var r2 = el.closest("div div");  
// returns the closest ancestor which is a div in div, here is div-03 itself

var r3 = el.closest("article > div");  
// returns the closest ancestor which is a div and has a parent article, here is div-01

var r4 = el.closest(":not(div)");
// returns the closest ancestor which is not a div, here is the outmost article
Run Code Online (Sandbox Code Playgroud)

  • 我发现除 Internet Explorer 之外的所有浏览器现在都支持“最接近”(2020 年 6 月)。 (4认同)
  • 对于最接近的 div 而不是它本身呢? (2认同)

mar*_*rix 12

基于8472答案https://developer.mozilla.org/en-US/docs/Web/API/Element/matches这里是跨平台2017解决方案:

if (!Element.prototype.matches) {
    Element.prototype.matches =
        Element.prototype.matchesSelector ||
        Element.prototype.mozMatchesSelector ||
        Element.prototype.msMatchesSelector ||
        Element.prototype.oMatchesSelector ||
        Element.prototype.webkitMatchesSelector ||
        function(s) {
            var matches = (this.document || this.ownerDocument).querySelectorAll(s),
                i = matches.length;
            while (--i >= 0 && matches.item(i) !== this) {}
            return i > -1;
        };
}

function findAncestor(el, sel) {
    if (typeof el.closest === 'function') {
        return el.closest(sel) || null;
    }
    while (el) {
        if (el.matches(sel)) {
            return el;
        }
        el = el.parentElement;
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)


Jos*_*osh 9

@rvighne解决方案运行良好,但正如评论中所指出的那样ParentElement,ClassList两者都存在兼容性问题.为了使它更兼容,我使用了:

function findAncestor (el, cls) {
    while ((el = el.parentNode) && el.className.indexOf(cls) < 0);
    return el;
}
Run Code Online (Sandbox Code Playgroud)
  • parentNode财产而不是parentElement财产
  • indexOf方法的className属性而不是contains在方法classList属性.

当然,indexOf只是在寻找该字符串的存在,它并不关心它是否是整个字符串.因此,如果你有另一个带有'祖先类型'类的元素,它仍会返回为找到'祖先',如果这对你来说是个问题,也许你可以使用正则表达式找到完全匹配.


Jam*_*mes 7

此解决方案适用于 IE9 及更高版本。

当您需要获取可能比给定元素向上几个级别的父容器时,这就像 jQuery 的parents() 方法,例如查找<form>clicked 的包含<button>。遍历父代,直到找到匹配的选择器,或者直到它到达<body>. 返回匹配的元素或<body>.

function parents(el, selector){
    var parent_container = el;
    do {
        parent_container = parent_container.parentNode;
    }
    while( !parent_container.matches(selector) && parent_container !== document.body );

    return parent_container;
}
Run Code Online (Sandbox Code Playgroud)