한 요소가 다른 요소에 포함되어 있는지 Javascript를 확인하는 방법


201

한 DOM 요소가 다른 DOM 요소의 자식인지 어떻게 확인할 수 있습니까? 이를위한 내장 된 방법이 있습니까? 예를 들면 다음과 같습니다.

if (element1.hasDescendant(element2)) 

또는

if (element2.hasParent(element1)) 

그렇지 않으면 어떤 아이디어가 이것을 수행 하는가? 또한 크로스 브라우저 여야합니다. 또한 자녀가 부모 아래에 여러 수준으로 중첩 될 수 있다고 언급해야합니다.



나는 JS가 오늘날 "실제 표준"이므로 "conatins"방법을 허용 된 답변으로 나타 내기 위해 허용 된 답변을 다시 확인해야한다고 생각합니다.
DavidTaubmann 18

답변:


219

업데이트 : 이제 이것을 달성하는 기본 방법이 있습니다. Node.contains(). 댓글과 아래 답변에서도 언급했습니다.

이전 답변 :

parentNode속성을 사용하면 작동합니다. 또한 크로스 브라우저 관점에서 보면 매우 안전합니다. 관계가 한 수준으로 알려진 경우 간단히 확인할 수 있습니다.

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

자식이 부모 내부에 임의로 중첩 될 수있는 경우 다음과 유사한 함수를 사용하여 관계를 테스트 할 수 있습니다.

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

답장을 보내 주셔서 감사합니다. 문제는 자녀가 부모 아래에 여러 수준으로 중첩 될 수 있다는 것입니다.
AJ.

@ AJ : 부모에게 자식을 임의로 깊숙이 중첩시키는 솔루션을 포함하도록 대답을 업데이트했습니다.
Asaph

228
누구든지 지금이 오는 경우 최신 브라우저의 기본 기능인 Node.contains ( developer.mozilla.org/en-US/docs/DOM/Node.contains ) 를 사용할 수 있습니다 .
Adam Heath

2
@JohnCarrell 없다 Node.contains(더 caniuse 페이지 불구하고)
gcampbell는

3
@Asaph 새로운 답변을 포함하도록 답변을 업데이트 해 주 Node.contains시겠습니까? :)

355

Node.contains이제는 표준이며 모든 브라우저에서 사용할 수 있으므로을 사용해야 합니다.

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


Node.hasParent (parent) 메소드는 불필요하지만 Node.prototype.hasParent = function (element) {return element.contains (this);};
llange

6
모바일 브라우저에서도 지원됩니까? mdn 문서에는 Android, Safari, IE 및 Opera에 대한 물음표가 있습니다.
thetallweeks

1
@thetallweeks-적어도 내 안드로이드 7에서 작동합니다.
Sphinxxx

5
당신은 적어도 예제를 추가 할 수있었습니다
Nino Škopac

2
이것은 좋은 answear이지만 예제는 정말 좋을 것입니다 :var parent = document.getElementById('menu'); var allElements = document.getElementsByTagName('a'); if (parent.contains(allElements[i]) { alert('Link is inside meni'); }
baron_bartek

45

방금 '광산'을 공유해야했습니다.

개념적으로 Asaph의 대답 과 동일하지만 (동일한 브라우저 간 호환성, 심지어 IE6에서도 이점이 있음) 크기가 훨씬 작거나 크기가 자주 필요하지 않을 때 유용합니다.

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

.. 또는 한 줄짜리 문자 ( 64 문자 만 !) :

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

그리고 여기에 jsfiddle .


사용법 :
childOf(child, parent) 부울true| false.

설명 :
while while 조건이로 평가되는 한 평가합니다true. (AND) 연산자 반환이 부울 참 / 거짓을 된 왼쪽과 오른쪽을 평가할 만 한다면 좌측이 사실 ( ) .
&&left-hand && right-hand

(의 &&) 의 왼쪽 은 다음과 같습니다 (c=c.parentNode).
먼저 parentNodeof c를 할당 c한 다음 AND 연산자가 결과 c를 부울로 평가합니다 .
이후 parentNode반환 null부모 왼쪽이없는 경우 null로 변환되어 false더 이상 부모가 없을 때 잠시 루프가 제대로 중지됩니다.

(의 &&) 의 오른쪽 은 다음과 같습니다 c!==p. 비교 연산자 '이다 하지 정확히 동일한'. 따라서 자녀의 부모가 부모 (지정한)가 아니면로 평가 되지만 자녀의 부모 부모이면 평가됩니다 . 그래서 경우 FALSE로는, 그 조작 복귀 그동안 조건과 같은 동안 루프는 정지한다. (몸통이 필요없고 닫는 세미콜론이 필요합니다.)
!==truefalse
c!==p&&false;

따라서 while 루프가 끝날 때 부모를 찾았을 때 c노드가 아니고 노드가 아닌 (루프가 일치하지 않고 끝까지 갔을 때)nullnull

따라서 단순히 우리 return와 (노드 대신, 부울 값 환산) 사실 : return !!c;다음 !( NOT오퍼레이터)은 부울 값 (반전 true된다 false반대로). 해당 값을 반전시키기 전에 (노드 또는 널)을 부울
!c로 변환 c합니다. 따라서 초 !( !!c)를 추가하면 이 false가 다시 true !!로 변환됩니다. 따라서 double 은 종종 '무언가로 변환'하는 데 사용됩니다.


추가 :
기능의 몸 / 페이로드는 너무 작아서,이 경우에 따라 하나가 (이 자주 사용하고 코드에 한 번만 표시되지 않은 경우 등) 수있는 기능 (포장)를 생략하고 바로 동안 루프를 사용하는 경우에도 :

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
}

대신에:

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 : 엄격한 동등성 비교 ( !==)는 느슨한 동등성 비교에서 발생할 수있는 형식 검사 및 선택적 암시 적 변환 단계를 건너 뛸 수 있음을 분명히하여 속도를 향상시킬 수 있습니다. 따라서 속도를 향상시킵니다. 프로그래머에게도 도움이됩니다. 나는 이것을 썼을 때를 떠올리는 것처럼 생각합니다. 느슨한 비교 ( !=) 만 오류가 발생하기 쉽거나 일부 구형 브라우저에서 전혀 작동하지 않았다는 것입니다 (IE6에 있다고 생각하지만 잊어 버렸습니다) ).
GitaarLAB

29

언급되지 않은 또 다른 솔루션 :

여기 예

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

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

요소가 직접적인 자식인지 여부는 중요하지 않으며 어떤 깊이에서도 작동합니다.


또는 다음 .contains()방법을 사용하십시오 .

여기 예

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

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

19

Node # compareDocumentPosition을 살펴보십시오 .

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

다른 관계를 포함 DOCUMENT_POSITION_DISCONNECTED, DOCUMENT_POSITION_PRECEDING하고 DOCUMENT_POSITION_FOLLOWING.

IE <= 8에서는 지원되지 않습니다.


흥미 롭다! 이것은 2003 년에 제가 개발 한 JS 함수를 생각 나게합니다. 며칠이 걸렸고 일부 JS 개발자의 도움을 받았습니다 ... 오늘날에도 여전히 완전한 끌어서 놓기 나 객체에 맞는 풀 브라우저 구현이 없다는 놀라운 (그리고 슬픈) .
DavidTaubmann


2

요소가 다른 요소의 자식인지 여부를 확인하기 위해 훌륭한 코드를 발견했습니다. IE는 .contains요소 메소드를 지원하지 않기 때문에 이것을 사용해야합니다 . 이것이 다른 사람들에게도 도움이되기를 바랍니다.

기능은 다음과 같습니다.

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

나는이 페이지에서 .contains를 포함하여 다른 모든 polyfill을 문자 그대로 시도했으며 이것이 유일하게 작동했습니다. 감사!
protoEvangelion 2018 년

1

이거 한번 해봐:

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.