JQuery olmadan en yakın öğeyi bulma


90

Jquery olmadan belirli bir etiket adıyla en yakın öğeyi bulmaya çalışıyorum. Bir üzerine tıkladığımda, o tabloya <th>erişmek istiyorum <tbody>. Öneriler? Ofset hakkında okudum ama pek anlamadım. Sadece kullanmalı mıyım:

Bunun zaten tıklanan öğeye ayarlandığını varsayın

th.offsetParent.getElementsByTagName('tbody')[0]

1
DOM üzerinden geçiş yapmaya başlamanız gerektiğini fark ederseniz, bu, jquery'ye atfedilen fazladan kb'lerin buna değeceği bir örnektir.
Kevin Bowersox


2
Bunun çok önemli ve geçerli bir soru olduğunu düşünüyorum. Olumsuz oylar için bir sebep yok.

el.closest('tbody')ie olmayan tarayıcılar için. Aşağıda daha ayrıntılı yanıt + çoklu doldurmaya bakın.
oriadam

Yanıtlar:


69

Partiye biraz (çok) geç, ama yine de. Bu hile yapmalı :

function closest(el, selector) {
    var matchesFn;

    // find vendor prefix
    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
        if (typeof document.body[fn] == 'function') {
            matchesFn = fn;
            return true;
        }
        return false;
    })

    var parent;

    // traverse parents
    while (el) {
        parent = el.parentElement;
        if (parent && parent[matchesFn](selector)) {
            return parent;
        }
        el = parent;
    }

    return null;
}

2
Bir muamele yapan harika cevap. MDN ayrıca element.closest () için bir polyfill'e sahiptir. Chrome, geçerli sürümde element.matches () içerir, bu nedenle ön ek gerekmez. Bunu geliştirdiğim bir uygulamada kullandığım bir kitaplığa ekledim, Clibu.
nevf

2
Kodu, eljQuery.closest () ve ayrıca Element.closest () 'in yaptığı öğeyi test edecek şekilde değiştirdim . for( var parent = el ; parent !== null && !parent[matchesFn](selector) ; parent = el.parentElement ){ el = parent; } return parent;
nevf

1
Bu kod iyi, ancak noktalı virgül eksik ve aynı zamanda parentgenel kapsamda tanımlıyor (!)
Steven Lu

1
Şunu belirtmeye değer olabilir: developer.mozilla.org/en-US/docs/Web/API/Element/closest destek konusunda biraz düşük olsa da en yakın yöntem için yerel yöntem: Chrome41, FF35, IE-nope, Opera28, Safari9
Michiel D

Bununla ilgili sadece bir not, yapmak isteyebilirsiniz, yoksa el.parentNodebu, IE'de bir SVG'yi geçerken bozulacaktır.
smcka

125

Çok basit:

el.closest('tbody')

IE dışındaki tüm tarayıcılarda desteklenir.
GÜNCELLEME : Edge şimdi de destekliyor.

JQuery'ye gerek yok. Dahası, jQuery'leri $(this).closest('tbody')ile değiştirmek $(this.closest('tbody')), öğe bulunmadığında performansı önemli ölçüde artıracaktır.

IE için Polyfill:

if (!Element.prototype.matches) Element.prototype.matches = Element.prototype.msMatchesSelector;
if (!Element.prototype.closest) Element.prototype.closest = function (selector) {
    var el = this;
    while (el) {
        if (el.matches(selector)) {
            return el;
        }
        el = el.parentElement;
    }
};

Unutmayın ki returnöğe bulunmadığında, undefineden yakın öğe bulunamadığında etkin bir şekilde geri döner.

Daha fazla ayrıntı için bkz: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest


4
Bu cevap neden sayfanın altında? En üstte olmalı. Çok teşekkürler
Julien Le Coupanec

en yakını jQuery'dedir, ancak OP jQuery yok diyor.
steve moretz

@kafadergisi. en yakın yerel JavaScript şimdi
Louise Eggleton

@LouiseEggleton Evet, oops
steve moretz

Buna en iyi cevap denir!
ChosenUser

22

JQuery olmadan etiket adına göre en yakın öğeyi şu şekilde elde edersiniz:

function getClosest(el, tag) {
  // this is necessary since nodeName is always in upper case
  tag = tag.toUpperCase();
  do {
    if (el.nodeName === tag) {
      // tag name is found! let's return it. :)
      return el;
    }
  } while (el = el.parentNode);

  // not found :(
  return null;
}

getClosest(th, 'tbody');

2
Bunun işe yarayacağına inanmıyorum. Yalnızca DOM ağacını kontrol eder. th-> thead-> tablo asla kardeşleri dikkate
almaz

2
Sorunuzda bu özel durumu belirtmelisiniz.
Joon

2
Bak. Bu işlev, sağlanan etiketi kullanan en yakın ebeveyni (uzantıya göre bile) bulmak için parentNodes üzerinde gezinir. Bu belge ağacında "aşağı" gitmez, yalnızca "yukarı" olur. Ortalama bir kullanıcı "en yakın" düğümü büyük olasılıkla en yakın kardeş olarak görür. Sadece ihtiyaç duyduğu terminolojiyi bilmiyor.

1
Adil olmak gerekirse @Jhawins'e en yakın tanımınız jQuery'nin en yakın terimidir. Bu bir jQuery sorusu değil. JQuery'nin neden en yakın anlamına gelen en yakın ataya karar verdiğini doğrulayamıyorum, ancak bu bir ebeveyn, önceki bir kardeş, sonraki bir kardeş vb. Olsun, daha makul bir tanım en yakın öğe olacaktır. Hedef öğeye "en yakın" bulunan her ne ise.
ryandlf

1
@ryandlf Peki ya hem ebeveyniniz hem de kardeşiniz aynı "mesafede" olsaydı? jQuery'nin tanımı, en fazla bir eşleşme döndüreceği için açıktır.
mtone

9

Bunu yapmak için standartlaştırılmış bir işlev vardır: Element.closest . IE11 dışındaki çoğu tarayıcı bunu destekler ( ayrıntılar caniuse.com ). MDN dokümanlar da eski tarayıcıları hedef sahip durumda bir polyfill sayılabilir.

En yakını bulmak için tbody ebeveynith şunları yapabilirsiniz:

th.closest('tbody');

Fonksiyonu kendiniz yazmak istemeniz durumunda - işte ortaya çıkardığım şey:

function findClosestParent (startElement, fn) {
  var parent = startElement.parentElement;
  if (!parent) return undefined;
  return fn(parent) ? parent : findClosestParent(parent, fn);
}

En yakın ebeveyni etiket adına göre bulmak için bunu şu şekilde kullanabilirsiniz:

findClosestParent(x, element => return element.tagName === "SECTION");

6
function closest(el, sel) {
    if (el != null)
        return el.matches(sel) ? el 
            : (el.querySelector(sel) 
                || closest(el.parentNode, sel));
}

Bu çözüm, HTML 5 spesifikasyonunun daha yeni özelliklerinden bazılarını kullanır ve bunu daha eski / uyumsuz tarayıcılarda (okuyun: Internet Explorer) kullanmak bir çoklu doldurma gerektirir.

Element.prototype.matches = (Element.prototype.matches || Element.prototype.mozMatchesSelector 
    || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector 
    || Element.prototype.webkitMatchesSelector || Element.prototype.webkitMatchesSelector);

Her zaman en üstteki ilk masaya gider. en yakın tablo değil .. bu bağlantıya bakın jsfiddle.net/guuy5kof
Balachandran

güzel yakalayış! düzeltildi, buraya bakın jsfiddle.net/c2pqc2x0 lütfen bana bir patron gibi oy verin :)
Matthew James Davis

evet yapmam ... Keman sonucunuzu kontrol ettiniz mi, hata gösteriyor .. eşleşmeler undefined
Balachandran

benim için harika çalışıyor, hangi tarayıcıda çalışıyorsunuz? bu eski tarayıcılarda desteklenmez
Matthew James Davis

hey, ne diyorsun olumsuz oyu açıklığa kavuşturalım kardeşim
Matthew James Davis

3

@SalmanPK yanıtını genişletmek için

düğümü seçici olarak kullanmanıza izin verir, fareyle üzerine gelme gibi olaylarla çalışırken yararlıdır.

function closest(el, selector) {
    if (typeof selector === 'string') {
        matches = el.webkitMatchesSelector ? 'webkitMatchesSelector' : (el.msMatchesSelector ? 'msMatchesSelector' : 'matches');
        while (el.parentElement) {
            if (el[matches](selector)) {
                return el
            };
            el = el.parentElement;
        }
    } else {
        while (el.parentElement) {
            if (el === selector) {
                return el
            };
            el = el.parentElement;
        }
    }

    return null;
}

2

İşte kullandığım basit işlev: -

function closest(el, selector) {
    var matches = el.webkitMatchesSelector ? 'webkitMatchesSelector' : (el.msMatchesSelector ? 'msMatchesSelector' : 'matches');

    while (el.parentElement) {
        if (el[matches](selector)) return el;

        el = el.parentElement;
    }

    return null;
}

2

Özet:

Belirli bir atayı bulmak için şunları kullanabiliriz:

Element.closest();

Bu işlev, bağımsız değişken olarak bir CSS seçici dizesi alır. daha sonra, bağımsız değişkenlerde iletilen CSS seçiciyle eşleşen geçerli öğenin (veya öğenin kendisinin) en yakın üst öğesini döndürür. Eğer ata yoksa geri dönecektir null.

Misal:

const child = document.querySelector('.child');
// select the child

console.dir(child.closest('.parent').className);
// check if there is any ancestor called parent
<div class="parent">
  <div></div>
  <div>
    <div></div>
    <div class="child"></div>
  </div>
</div>


1

Ağaçta bir sınıf, kimlik, veri özelliği veya etiket içeren en yakın DOM öğesini alın. Öğenin kendisini içerir. IE6'ya geri desteklenir.

var getClosest = function (elem, selector) {

    var firstChar = selector.charAt(0);

    // Get closest match
    for ( ; elem && elem !== document; elem = elem.parentNode ) {

        // If selector is a class
        if ( firstChar === '.' ) {
            if ( elem.classList.contains( selector.substr(1) ) ) {
                return elem;
            }
        }

        // If selector is an ID
        if ( firstChar === '#' ) {
            if ( elem.id === selector.substr(1) ) {
                return elem;
            }
        } 

        // If selector is a data attribute
        if ( firstChar === '[' ) {
            if ( elem.hasAttribute( selector.substr(1, selector.length - 2) ) ) {
                return elem;
            }
        }

        // If selector is a tag
        if ( elem.tagName.toLowerCase() === selector ) {
            return elem;
        }

    }

    return false;

};

var elem = document.querySelector('#some-element');
var closest = getClosest(elem, '.some-class');
var closestLink = getClosest(elem, 'a');
var closestExcludingElement = getClosest(elem.parentNode, '.some-class');

Neden firstChartüm IFkoşullar yerine bir anahtar kullanmıyorsunuz ?
Rafael Herscovici

Neden belirsiz bir fordöngü kullanıyorsunuz?
Rafael Herscovici

1

En yakın Elements childNodes'unu bulun.

closest:function(el, selector,userMatchFn) {
var matchesFn;

// find vendor prefix
['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
    if (typeof document.body[fn] == 'function') {
        matchesFn = fn;
        return true;
    }
    return false;
});
function findInChilds(el){
    if(!el) return false;
    if(el && el[matchesFn] && el[matchesFn](selector)

    && userMatchFn(el) ) return [el];
    var resultAsArr=[];
    if(el.childNodes && el.childNodes.length){
        for(var i=0;i< el.childNodes.length;i++)
        {
             var child=el.childNodes[i];
             var resultForChild=findInChilds(child);
            if(resultForChild instanceof Array){
                for(var j=0;j<resultForChild.length;j++)
                {
                    resultAsArr.push(resultForChild[j]);
                }
            } 
        }

    }
    return resultAsArr.length?resultAsArr: false;
}

var parent;
if(!userMatchFn || arguments.length==2) userMatchFn=function(){return true;}
while (el) {
    parent = el.parentElement;
    result=findInChilds(parent);
    if (result)     return result;

    el = parent;
}

return null;

}


0

Buraya.

function findNearest(el, tag) {
    while( el && el.tagName && el.tagName !== tag.toUpperCase()) {
        el = el.nextSibling;     
    } return el;
} 

Sadece ağacın aşağısında kardeşleri bulur. Diğer yöne gitmek için previousSibling'i kullanın Veya her iki yolu da geçmek ve hangisi önce bulunursa geri dönmek için değişkenleri kullanın. Genel fikri anlıyorsunuz, ancak bir kardeş eşleşmiyorsa parentNodes veya çocuklarda gezinmek istiyorsanız jQuery'yi de kullanabilirsiniz. Bu noktada kolayca buna değer.


0

Partiye biraz geç kaldım, ama oradan geçerken ve çok benzer bir soruyu yanıtlarken, buraya çözümümü bırakıyorum - bunun JQuery closest()yaklaşımı olduğunu söyleyebiliriz , ancak çok iyi JavaScript.

Herhangi bir pollyfill'e ihtiyaç duymaz ve daha eski tarayıcılara sahiptir ve IE (:-)) dostu: https://stackoverflow.com/a/48726873/2816279


-4

Bence en yakın jquery ile yakalamak için en kolay kod:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
    $(document).ready(function () {
        $(".add").on("click", function () {
            var v = $(this).closest(".division").find("input[name='roll']").val();
            alert(v);
        });
    });
</script>
<?php

for ($i = 1; $i <= 5; $i++) {
    echo'<div class = "division">'
        . '<form method="POST" action="">'
        . '<p><input type="number" name="roll" placeholder="Enter Roll"></p>'
        . '<p><input type="button" class="add" name = "submit" value = "Click"></p>'
        . '</form></div>';
}
?>

Çok teşekkürler.

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.