Belirli bir sınıfa sahip en yakın ata öğesini bulun


225

Belirli bir sınıfa sahip olan ağaca en yakın olan bir öğenin atalarını saf JavaScript'te nasıl bulabilirim? Örneğin, böyle bir ağaçta:

<div class="far ancestor">
    <div class="near ancestor">
        <p>Where am I?</p>
    </div>
</div>

Sonra ben div.near.ancestorbunu denemek pve aramak istiyorum ancestor.


1
dış div'in bir ebeveyn olmadığını, öğenin bir atası olduğunu lütfen unutmayın p. Aslında sadece üst düğümü almak istiyorsanız, bunu yapabilirsiniz ele.parentNode.
Felix Kling

@FelixKling: Bu terminolojiyi bilmiyordum; Değiştireceğim.
rvighne

3
Aslında biz insanların kullandıkları ile aynıdır :) Babanızın (ebeveyn) babası (ebeveyn) babanız (ebeveyn) değil, büyükbabanız (büyükbaba veya büyükbaba) veya daha genel olarak konuşursak, atalarınızdır.
Felix Kling

Yanıtlar:


346

Güncelleme: Artık çoğu büyük tarayıcıda destekleniyor

document.querySelector("p").closest(".near.ancestor")

Bunun yalnızca sınıflarla değil seçicilerle eşleşebileceğini unutmayın

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


Desteklemeyen, closest()ancak desteklemeyen eski tarayıcılar matches()için @ rvighne sınıf eşleşmesine benzer bir seçici eşleme oluşturabilir:

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

1
Internet Explorer, Edge ve Opera Mini'nin güncel sürümlerinde hala desteklenmemektedir.
kleinfreund

1
@kleinfreund - IE, Edge veya Opera mini'de hala desteklenmemektedir. caniuse.com/#search=closest
evolutionxbox

8
Haziran 2016: Görünüşe göre tüm tarayıcılar hala yakalanmadı
Kunal

3
Bir DOM Level 4closest çoklu dolgusu ve daha birçok gelişmiş DOM geçiş özelliği var. Kodunuzda birçok yeni özellik elde etmek için bu uygulamayı kendi başınıza çekebilir veya paketin tamamını ekleyebilirsiniz.
Garbee

2
Edge 15, tüm büyük tarayıcıları kapsaması gereken bir desteğe sahiptir. IE11 sayamazsanız, ancak bu herhangi bir güncelleme
almazsa

195

Bu hile yapar:

function findAncestor (el, cls) {
    while ((el = el.parentElement) && !el.classList.contains(cls));
    return el;
}

Kadar döngü bekler iken elistenen sınıfı vardır ve ayarlar eliçin elsonuna kadar bireyin ebeveyn her yinelemesini, o sınıfın veya atası var null.

İşte birisi onu geliştirmek istiyorsa, bir keman . Eski tarayıcılarda (IE) çalışmaz; classList için bu uyumluluk tablosuna bakın . parentElementburada kullanılır, çünkü parentNodedüğümün bir eleman olduğundan emin olmak için daha fazla çalışma gerektirir.


1
Alternatifi için .classListbkz. Stackoverflow.com/q/5898656/218196 .
Felix Kling

1
Kodu düzelttim, ancak böyle bir sınıf adına sahip bir ata yoksa hala bir hata atardı.
Felix Kling

2
Bunun olmadığını düşündüm, ama yanılmışım . Her neyse, parentElementoldukça yeni bir özellik (DOM seviye 4) ve parentNodeo zamandan beri var ... sonsuza dek. Bu yüzden parentNodeeski tarayıcılarda da çalışır, ancak parentElementolmayabilir. Tabii ki / argümanı için aynı argümanı yapabilirsin classList, ama onun gibi basit bir alternatifi yok parentElement. Aslında neden parentElementvar olduğunu merak ediyorum , herhangi bir değer katmıyor gibi görünüyor parentNode.
Felix Kling

1
@FelixKling: Yeni düzenlendi, şimdi böyle bir ata olmadığında durum için iyi çalışıyor. Kısa orijinal versiyon ile aşırıya kaçmış olmalıydım.
rvighne

3
Parametre öğesinin kendisinde sınıf adını kontrol etmek istiyorsanız, atalarını aramadan önce, döngüdeki koşulların sırasını değiştirebilirsiniz:while (!el.classList.contains(cls) && (el = el.parentElement));
Nicomak

34

Element.closest () öğesini kullanın

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

Bu örnek DOM'ya bakın:

<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 yöntemini şu şekilde kullanırsınız:

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

Internet explorer dışındaki tüm tarayıcıların artık 'en yakın' (Haziran 2020) desteği olduğunu görüyorum.
user2677034

14

Dayanarak the8472 cevap ve https://developer.mozilla.org/en-US/docs/Web/API/Element/matches burada çapraz platforma 2017 çözümü geçerli:

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;
}

11

@rvighne çözümü iyi çalışıyor, ancak yorumlarda belirtildiği gibi ParentElementve ClassListher ikisinin de uyumluluk sorunları var. Daha uyumlu hale getirmek için kullandım:

function findAncestor (el, cls) {
    while ((el = el.parentNode) && el.className.indexOf(cls) < 0);
    return el;
}
  • parentNodeözellik yerine parentElementözellik
  • indexOfyöntem üzerinde classNameözellik yerine containsyöntem classList.

Tabii ki, indexOf sadece bu dizenin varlığını arıyor, dizenin tamamı olup olmadığını umursamıyor. Eğer 'ancestor-type' sınıfına sahip başka bir elemanınız varsa, yine de 'atası' bulmuş gibi geri dönecektir, eğer bu sizin için bir problemse, belki de tam bir eşleşme bulmak için regexp kullanabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.