Bir öğe diğerinin içinde bulunuyorsa Javascript'te nasıl kontrol edilir


202

Bir DOM öğesinin başka bir DOM öğesinin alt öğesi olup olmadığını nasıl kontrol edebilirim? Bunun için yerleşik yöntemler var mı? Örneğin, şöyle bir şey:

if (element1.hasDescendant(element2)) 

veya

if (element2.hasParent(element1)) 

Değilse, bunu nasıl yapacağınız hakkında bir fikir? Ayrıca çapraz tarayıcı olması gerekir. Çocuğun ebeveynin altında birçok seviyeye yuvalanabileceğini de belirtmeliyim.



JS bugünlerde bir "canlı standart" olduğu için kabul edilen cevabın kabul edilen cevap olarak "conatins" yöntemini tekrar kontrol etmesi gerektiğine inanıyorum.
DavidTaubmann

Yanıtlar:


220

Güncelleme: Bunu başarmanın yerel bir yolu var. Node.contains(). Yorumda ve aşağıdaki cevaplarda da bahsedilmiştir.

Eski cevap:

parentNodeMülkü kullanmak çalışmalıdır. Tarayıcılar arası bir bakış açısından da oldukça güvenlidir. İlişkinin bir seviye derinliği olduğu biliniyorsa, basitçe kontrol edebilirsiniz:

if (element2.parentNode == element1) { ... }

Çocuk keyfi olarak ebeveynin derinliklerine yuvalanabilirse, ilişkiyi test etmek için aşağıdakine benzer bir işlev kullanabilirsiniz:

function isDescendant(parent, child) {
     var node = child.parentNode;
     while (node != null) {
         if (node == parent) {
             return true;
         }
         node = node.parentNode;
     }
     return false;
}

Cevabınız için teşekkürler, sorun çocuğun ebeveynin altında birçok seviyeye yuvalanmış olabilmesidir.
AJ.

@ AJ: Cevabımı, çocuğu keyfi olarak ebeveynin derinliklerine yerleştirmek için çalışması gereken bir çözüm içerecek şekilde güncelledim.
Asaph

228
Şimdi buna kimse geliyorsa , modern tarayıcılarda yerel bir işlev olan Node.contains'ı ( developer.mozilla.org/en-US/docs/DOM/Node.contains ) kullanmanız mümkün olabilir .
Adam Heath

2
@JohnCarrell Node.contains(gerçi caniuse sayfası yok)
gcampbell

3
@Asaph Cevabınızı yenisini içerecek şekilde güncelleyebilir misiniz Node.contains? :)

355

Kullanmanız gerekir Node.contains, çünkü artık standart ve tüm tarayıcılarda kullanılabilir.

https://developer.mozilla.org/en-US/docs/Web/API/Node.contains


Node.hasParent (parent) yöntemi gereksizdir ancak Node.prototype.hasParent = function (element) {return element.contains (this);};
llange

6
Mobil tarayıcılarda da destekleniyor mu? Mdn belgelerinde Android, Safari, IE ve Opera için soru işaretleri bulunur.
thetallweeks

1
@thetallweeks - En azından Android 7 cihazımda çalışıyor.
Sfenxxx

5
en azından bir örnek
ekleyebilirdiniz

2
Bu iyi cevap ama örnek gerçekten güzel olurdu:var parent = document.getElementById('menu'); var allElements = document.getElementsByTagName('a'); if (parent.contains(allElements[i]) { alert('Link is inside meni'); }
baron_bartek

45

Sadece benimkini paylaşmak zorunda kaldım.

Kavramsal olarak Asaph'ın cevabı ile aynı olsa da (aynı tarayıcılar arası uyumluluktan, hatta IE6'dan yararlanarak), çok daha küçüktür ve boyut premium olduğunda ve / veya çok sık ihtiyaç duyulmadığında kullanışlı olur.

function childOf(/*child node*/c, /*parent node*/p){ //returns boolean
  while((c=c.parentNode)&&c!==p); 
  return !!c; 
}

..ya da tek astar olarak ( sadece 64 karakter !):

function childOf(c,p){while((c=c.parentNode)&&c!==p);return !!c}

ve burada jsfiddle .


Kullanım:
childOf(child, parent) boolean döndürürtrue| false.

Açıklama:
while while koşulu değerlendirildiği sürece değerlendirirtrue. (AND) operatörü döner bu boole doğru / yanlış sonra sol tarafını ve sağ tarafını değerlendirirken, fakat sadece eğer sol taraftaki doğruydu ( ) .
&&left-hand && right-hand

(Sol taraftaki &&) aşağıdaki gibidir: (c=c.parentNode).
Bu, ilk atar parentNodeait cetmek cve daha sonra VE operatör çıkan değerlendirecek cboolean olarak.
Yana parentNodegetiri nullhiçbir ebeveyn sol varsa ve nulldönüştürülür falseartık anne varken iken döngü doğru duracak.

(Sağ taraftaki &&) aşağıdaki gibidir: c!==p. Karşılaştırma operatörü 'dir değil tam karşı eşit'. Çocuğun ebeveyn ana (belirttiğiniz) o olarak değerlendirilir değildir Yani eğer , ancak çocuğun ebeveyn eğer olduğunu ebeveyn o zaman olarak değerlendirilirse . Dolayısıyla, eğer false olarak değerlendirilirse, operatör while koşulu olarak döner ve while döngüsü durur. (Bir süre gövdesine gerek olmadığını ve kapanış noktalı virgülünün gerekli olduğunu unutmayın.)
!==truefalse
c!==p&&false;

Bu yüzden while döngüsü sona erdiğinde, bir üst öğe VEYA bulduğunda cbir düğümdür (değil null) null(döngü eşleşme bulmadan sonuna kadar koştuğunda).

Bu nedenle sadece biz returnile (yerine düğümün, mantıksal bir değer olarak dönüştürülmüş) aslında: return !!c;: !( NOToperatörü) bir Boole değeri (ters çevirir trueolur falseve tam tersi).
!cdönüştürür cbir mantıksal değere (düğüm veya boş) bu değer tersine önce. Yani bir ikinci !( !!c) eklemek bu yanlışı tekrar doğruya dönüştürür (bu yüzden bir çift !!genellikle 'herhangi bir şeyi boole'ye dönüştürmek için kullanılır).


Ekstra:
işlevin vücut / yük çok küçük, bu durumda bağlı bir (genellikle kullanılan ve kod sadece bir kez görünür değilken gibi) olabilir fonksiyonunu (sarma) ihmal ve sadece while-döngü kullansalar bile:

var a=document.getElementById('child'),
    b=document.getElementById('parent'),
    c;

c=a; while((c=c.parentNode)&&c!==b); //c=!!c;

if(!!c){ //`if(c)` if `c=!!c;` was used after while-loop above
    //do stuff
}

onun yerine:

var a=document.getElementById('child'),
    b=document.getElementById('parent'),
    c;

function childOf(c,p){while((c=c.parentNode)&&c!==p);return !!c}

c=childOf(a, b);    

if(c){ 
    //do stuff
}

4
@SolomonUcko: Sıkı eşitlik karşılaştırması ( !==), derleyiciye gevşek bir eşitlik karşılaştırmasında oluşabilecek tür denetimini ve isteğe bağlı örtük dönüştürme adımlarını atlayabildiğini açıklayarak hızı artırabilir, böylece hızı iyileştirir ( olmasını istiyorum, ki bu da programcı için faydalıdır). Ben de bunu yazarken hatırlıyorum gibi, sadece gevşek karşılaştırma ( !=) ya çok hata eğilimli olduğunu ya da bazı eski tarayıcılarda işe yaramadı (IE6'da olduğundan şüpheleniyorum, ama unuttum ).
GitaarLAB

29

Bahsedilmeyen başka bir çözüm:

Buraya Örnek

var parent = document.querySelector('.parent');

if (parent.querySelector('.child') !== null) {
    // .. it's a child
}

Elemanın doğrudan bir çocuk olup olmadığı önemli değildir, herhangi bir derinlikte çalışacaktır.


Alternatif olarak, .contains()yöntemi kullanarak :

Buraya Örnek

var parent = document.querySelector('.parent'),
    child = document.querySelector('.child');

if (parent.contains(child)) {
    // .. it's a child
}

19

Node # comparDocumentPosition'a bir göz atın .

function isDescendant(ancestor,descendant){
    return ancestor.compareDocumentPosition(descendant) & 
        Node.DOCUMENT_POSITION_CONTAINS;
}

function isAncestor(descendant,ancestor){
    return descendant.compareDocumentPosition(ancestor) & 
        Node.DOCUMENT_POSITION_CONTAINED_BY;
}

Diğer ilişkiler dahil DOCUMENT_POSITION_DISCONNECTED, DOCUMENT_POSITION_PRECEDINGve DOCUMENT_POSITION_FOLLOWING.

IE'de desteklenmez <= 8.


ilginç! Bu bana 2003 yılında geliştirdiğim bir JS işlevini hatırlatıyor ... Birkaç gün sürdü ve bazı JS geliştiricilerinden yardım aldı ... Bugünlerde hala tam bir sürükle bırak veya nesneye tam tam tarayıcı uygulaması olmadığı inanılmaz (ve üzgün) .
DavidTaubmann


2

Bir öğenin başka bir öğenin çocuğu olup olmadığını kontrol etmek için harika bir kod parçasına rastladım. IE .containselement yöntemini desteklemediği için bunu kullanmak zorunda . Umarım bu başkalarına da yardımcı olur.

Aşağıda işlevi:

function isChildOf(childObject, containerObject) {
  var returnValue = false;
  var currentObject;

  if (typeof containerObject === 'string') {
    containerObject = document.getElementById(containerObject);
  }
  if (typeof childObject === 'string') {
    childObject = document.getElementById(childObject);
  }

  currentObject = childObject.parentNode;

  while (currentObject !== undefined) {
    if (currentObject === document.body) {
      break;
    }

    if (currentObject.id == containerObject.id) {
      returnValue = true;
      break;
    }

    // Move up the hierarchy
    currentObject = currentObject.parentNode;
  }

  return returnValue;
}

Kelimenin tam anlamıyla .contains da dahil olmak üzere bu sayfada diğer tüm çoklu doldurmayı denedim ve bu işe yarayan tek şey. Teşekkürler!
protoEvangelion

1

bunu dene:

x = document.getElementById("td35");
if (x.childElementCount > 0) {
    x = document.getElementById("LastRow");
    x.style.display = "block";
}
else {
    x = document.getElementById("LastRow");
    x.style.display = "none";
}

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.