특정 클래스가있는 가장 가까운 조상 요소 찾기


225

순수 JavaScript에서 특정 클래스가있는 트리에 가장 가까운 요소의 조상을 어떻게 찾을 수 있습니까? 예를 들어, 다음과 같은 나무에서 :

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

그런 다음에 이것을 div.near.ancestor시도 p하고를 검색 하고 싶습니다 ancestor.


1
그것은이다, 외부 DIV 부모 아님을 유의하시기 바랍니다 조상 받는 p요소입니다. 실제로 부모 노드 만 가져 오려면 할 수 있습니다 ele.parentNode.
Felix Kling

@FelixKling : 그 용어를 몰랐습니다. 변경하겠습니다.
rvighne

3
그것은 실제로 우리 인간이 사용하는 것과 동일합니다.
Felix Kling

답변:


346

업데이트 : 대부분의 주요 브라우저에서 지원

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

1
현재 버전의 Internet Explorer, Edge 및 Opera Mini에서는 여전히 지원되지 않습니다.
kleinfreund

1
@kleinfreund-IE, Edge 또는 Opera mini에서는 여전히 지원되지 않습니다. caniuse.com/#search=closest
evolutionxbox

8
2016 년 6 월 : 모든 브라우저가 여전히 따라 잡지 않은 것 같습니다
Kunal

3
DOM 레벨 4 와 polyfill closest플러스 더 많은 고급 DOM 탐색 기능. 해당 구현을 자체적으로 가져 오거나 전체 번들을 포함시켜 코드에서 많은 새로운 기능을 얻을 수 있습니다.
Garbee

2
Edge 15는 모든 주요 브라우저를 지원해야합니다. IE11을 세지 않으면 업데이트를받지 않습니다
the8472

195

이것은 트릭을 수행합니다.

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

때까지 루프 대기하면서 el원하는 클래스를 가지고 있으며,이 설정 elel결국 지금의 부모마다 반복을 해당 클래스 또는 함께 조상을 가지고 null.

누군가가 그것을 향상시키고 싶다면 바이올린이 있습니다. 오래된 브라우저 (예 : IE)에서는 작동하지 않습니다. classList의 호환성 테이블을 참조하십시오 . 노드가 요소인지 확인하기 위해 더 많은 작업이 필요 parentElement하므로 여기에서 사용됩니다 parentNode.


1
에 대한 대안 .classListstackoverflow.com/q/5898656/218196을 참조하십시오 .
Felix Kling

1
코드를 수정했지만 이러한 클래스 이름을 가진 조상이 없으면 여전히 오류가 발생합니다.
Felix Kling

2
어, 나는 그것이 존재하지 않는다고 생각 했지만 잘못되었습니다 . 어쨌든, parentElement다소 새로운 재산 (DOM 레벨 4)이며 그 parentNode이후로 영원히 존재합니다. 따라서 parentNode이전 브라우저에서도 작동하지만 parentElement그렇지 않을 수도 있습니다. 물론 / against와 동일한 인수를 만들 수는 classList있지만 have와 같은 간단한 대안은 없습니다 parentElement. 나는 실제로 왜 parentElement존재 하는지 궁금 합니다 parentNode. 이상의 가치를 추가하지 않는 것 같습니다 .
Felix Kling

1
@FelixKling : 방금 편집되었으므로 이제 그러한 조상이 존재하지 않는 경우에 잘 작동합니다. 나는 짧은 원본 버전을 간절히 바 랐을 것입니다.
rvighne

3
조상을 검색하기 전에 매개 변수 요소 자체에서 클래스 이름을 확인하려면 루프에서 조건 순서를 간단히 전환하면됩니다.while (!el.classList.contains(cls) && (el = el.parentElement));
Nicomak

34

사용 ) (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

14

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

11

@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'이있는 다른 요소가있는 경우 여전히 '조상'을 찾은 것으로 반환됩니다.이 문제가있는 경우 regexp를 사용하여 정확하게 일치하는 것을 찾을 수 있습니다.

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