[英]Find the closest ancestor element that has a specific class
How can I find an element's ancestor that is closest up the tree that has a particular class, in pure JavaScript ?如何在纯 JavaScript 中找到最靠近具有特定类的树的元素的祖先? For example, in a tree like so:
例如,在这样的树中:
<div class="far ancestor">
<div class="near ancestor">
<p>Where am I?</p>
</div>
</div>
Then I want div.near.ancestor
if I try this on the p
and search for ancestor
.然后我想要
div.near.ancestor
如果我在p
上尝试这个并搜索ancestor
。
Update: Now supported in most major browsers更新:现在大多数主流浏览器都支持
document.querySelector("p").closest(".near.ancestor")
Note that this can match selectors, not just classes请注意,这可以匹配选择器,而不仅仅是类
https://developer.mozilla.org/en-US/docs/Web/API/Element.closest https://developer.mozilla.org/en-US/docs/Web/API/Element.closest
For legacy browsers that do not support closest()
but have matches()
one can build selector-matching similar to @rvighne's class matching:对于不支持
closest()
但有matches()
旧浏览器,可以构建类似于@rvighne 的类匹配的选择器匹配:
function findAncestor (el, sel) {
while ((el = el.parentElement) && !((el.matches || el.matchesSelector).call(el,sel)));
return el;
}
This does the trick:这是诀窍:
function findAncestor (el, cls) {
while ((el = el.parentElement) && !el.classList.contains(cls));
return el;
}
The while loop waits until el
has the desired class, and it sets el
to el
's parent every iteration so in the end, you have the ancestor with that class or null
. while 循环一直等到
el
具有所需的类,并且每次迭代都会将el
设置为el
的父级,因此最后,您将拥有该类或null
的祖先。
Here's a fiddle , if anyone wants to improve it.这是一个小提琴,如果有人想改进它。 It won't work on old browsers (ie IE);
它不适用于旧浏览器(即 IE); see this compatibility table for classList .
请参阅classList 的兼容性表。
parentElement
is used here because parentNode
would involve more work to make sure that the node is an element.此处使用
parentElement
是因为parentNode
将涉及更多工作以确保该节点是一个元素。
Use element.closest()使用element.closest()
https://developer.mozilla.org/en-US/docs/Web/API/Element/closest https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
See this example DOM:请参阅此示例 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>
This is how you would use element.closest:这是您使用 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
Based on the the8472 answer and https://developer.mozilla.org/en-US/docs/Web/API/Element/matches here is cross-platform 2017 solution:基于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 solution works well, but as identified in the comments ParentElement
and ClassList
both have compatibility issues. @rvighne 解决方案运行良好,但正如评论中
ParentElement
和ClassList
都存在兼容性问题。 To make it more compatible, I have used:为了使其更兼容,我使用了:
function findAncestor (el, cls) {
while ((el = el.parentNode) && el.className.indexOf(cls) < 0);
return el;
}
parentNode
property instead of the parentElement
property parentNode
属性而不是parentElement
属性indexOf
method on the className
property instead of the contains
method on the classList
property. className
属性上的indexOf
方法,而不是classList
属性上的contains
方法。 Of course, indexOf is simply looking for the presence of that string, it does not care if it is the whole string or not.当然, indexOf 只是寻找该字符串的存在,它并不关心它是否是整个字符串。 So if you had another element with class 'ancestor-type' it would still return as having found 'ancestor', if this is a problem for you, perhaps you can use regexp to find an exact match.
因此,如果您有另一个具有“祖先类型”类的元素,它仍然会返回找到“祖先”,如果这对您来说是个问题,也许您可以使用正则表达式来查找精确匹配项。
This solution should work for IE9 and up.此解决方案应该适用于 IE9 及更高版本。
It's like jQuery's parents() method when you need to get a parent container which might be up a few levels from the given element, like finding the containing <form>
of a clicked <button>
.当您需要获取一个父容器时,它就像 jQuery 的 parents() 方法,该父容器可能比给定元素高几个级别,例如找到单击的
<button>
的包含<form>
<button>
。 Looks through the parents until the matching selector is found, or until it reaches the <body>
.查看父级,直到找到匹配的选择器,或者直到它到达
<body>
。 Returns either the matching element or the <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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.