如何在纯JavaScript中找到与具有特定类的树最接近的元素的祖先?例如,在像这样的树中:
<div class="far ancestor">
<div class="near ancestor">
<p>Where am I?</p>
</div>
</div>
然后,我想div.near.ancestor
在上尝试p
并搜索ancestor
。
如何在纯JavaScript中找到与具有特定类的树最接近的元素的祖先?例如,在像这样的树中:
<div class="far ancestor">
<div class="near ancestor">
<p>Where am I?</p>
</div>
</div>
然后,我想div.near.ancestor
在上尝试p
并搜索ancestor
。
Answers:
更新:大多数主流浏览器现在都支持
document.querySelector("p").closest(".near.ancestor")
请注意,这可以匹配选择器,而不仅仅是类
https://developer.mozilla.org/zh-CN/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;
}
closest
许多更高级的DOM遍历功能。您可以单独实现该实现,也可以包括整个捆绑包,以在代码中获得许多新功能。
这可以解决问题:
function findAncestor (el, cls) {
while ((el = el.parentElement) && !el.classList.contains(cls));
return el;
}
while循环等待直到el
拥有所需的类,并且每次迭代都将其设置el
为el
的父类,因此最后,您的祖先拥有该类或null
。
如果有人想改进它,这是一个小提琴。它不能在旧的浏览器(即IE)上运行;有关classList的信息,请参见此兼容性表。parentElement
之所以在此处使用,是因为parentNode
会涉及更多工作,以确保该节点是一个元素。
.classList
,请参见stackoverflow.com/q/5898656/218196。
parentElement
是一个相当新的属性(DOM级别4),并且parentNode
从...一直存在。所以parentNode
在较旧的浏览器中也可以,但是parentElement
可能不行。当然,您可以针对/ against输入相同的参数classList
,但它没有parentElement
has 那样的简单替代方法。我实际上想知道为什么parentElement
存在,它似乎并没有增加任何价值parentNode
。
while (!el.classList.contains(cls) && (el = el.parentElement));
使用element.closest()
https://developer.mozilla.org/zh-CN/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>
这就是使用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
基于the8472答案和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;
}
@rvighne解决方案效果很好,但正如注释中所指出的ParentElement
,ClassList
两者都存在兼容性问题。为了使其更加兼容,我使用了:
function findAncestor (el, cls) {
while ((el = el.parentNode) && el.className.indexOf(cls) < 0);
return el;
}
parentNode
属性而不是parentElement
属性indexOf
方法的className
属性而不是contains
在方法classList
属性。当然,indexOf只是在寻找该字符串的存在,它不在乎是否是整个字符串。因此,如果您有另一个具有类'ancestor-type'的元素,它仍会以找到'ancestor'的形式返回,如果这对您来说是个问题,也许您可以使用regexp来查找完全匹配。
p
。如果您实际上只想获取父节点,则可以这样做ele.parentNode
。