純粋な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
。
回答:
更新:ほとんどの主要ブラウザでサポートされるようになりました
document.querySelector("p").closest(".near.ancestor")
これはクラスだけでなくセレクターにも一致することに注意してください
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;
}
これはトリックを行います:
function findAncestor (el, cls) {
while ((el = el.parentElement) && !el.classList.contains(cls));
return el;
}
whileループel
は、希望するクラスが存在するまで待機し、反復ごとにの親に設定el
するel
ため、最終的には、そのクラスの祖先またはを使用できnull
ます。
誰かがそれを改善したいなら、ここにフィドルがあります。古いブラウザ(IEなど)では動作しません。classListについては、この互換性テーブルを参照してください。ノードが要素であることを確認するためにさらに多くの作業が必要になるparentElement
ためparentNode
、ここで使用されます。
parentElement
はかなり新しいプロパティ(DOMレベル4)でparentNode
あり、...ずっと存在しています。したがってparentNode
、古いブラウザでも機能しますが、機能しparentElement
ない場合があります。もちろん、/に対して同じ議論をすることもできますがclassList
、parentElement
hasのような単純な選択肢はありません。なぜparentElement
存在するのか、実際には何の価値もないように思えますparentNode
。
while (!el.classList.contains(cls) && (el = el.parentElement));
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>
これは、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'が見つかったとして返されます。これが問題である場合は、正規表現を使用して完全一致を見つけることができます。
p
。実際に親ノードのみを取得したい場合は、を実行できますele.parentNode
。