jQuery없이 가장 가까운 요소 찾기


90

jquery없이 특정 태그 이름을 가진 가장 가까운 요소를 찾으려고합니다. 를 클릭하면 해당 테이블에 대한 <th>액세스 권한을 얻고 싶습니다 <tbody>. 제안? 오프셋에 대해 읽었지만 너무 많이 이해하지 못했습니다. 그냥 사용해야할까요?

th가 이미 클릭 된 요소로 설정되어 있다고 가정합니다.

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

1
DOM을 통해 탐색을 시작해야하는 경우 jquery에 귀속되는 추가 kbs가 가치가있는 하나의 인스턴스입니다.
Kevin Bowersox 2013 년


2
이것은 매우 중요하고 유효한 질문이라고 생각합니다. 비추천 할 이유가 없습니다.

el.closest('tbody')IE가 아닌 브라우저의 경우. 아래에서 더 자세한 답변 + polyfill을 참조하십시오.
oriadam

답변:


69

파티에 조금 늦었지만 그럼에도 불구하고. 이것은 트릭을 해야합니다 .

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
대우를 작동하는 훌륭한 대답. MDN에는 element.closest ()에 대한 polyfill도 있습니다. Chrome에는 현재 릴리스에 element.matches ()가 포함되어 있으므로 접두사가 필요하지 않습니다. 내가 개발중인 앱인 Clibu에서 사용중인 lib에 이것을 방금 추가했습니다.
nevf 2015 년

2
eljQuery.closest () 및 Element.closest ()가 수행하는 요소도 테스트하도록 코드를 변경했습니다 . for( var parent = el ; parent !== null && !parent[matchesFn](selector) ; parent = el.parentElement ){ el = parent; } return parent;
nevf

1
이 코드는 괜찮지 만, 그것은 세미콜론 누락 또한 정의하는 것 parent전역 범위에서 (!)
스티븐 루

1
언급할만한 가치가 있습니다 : developer.mozilla.org/en-US/docs/Web/API/Element/closest 가장 가까운 기본 방법 : Chrome41, FF35, IE-nope, Opera28, Safari9
Michiel D

이것에 대한 참고 사항 el.parentNode은 IE에서 SVG를 탐색 할 때 수행하고 싶을 수 있습니다 .
smcka

125

매우 간단합니다.

el.closest('tbody')

IE를 제외한 모든 브라우저에서 지원됩니다.
업데이트 : Edge도 이제 지원합니다.

jQuery가 필요 없습니다. 더 이상 교체 jQuery를이다 $(this).closest('tbody')$(this.closest('tbody'))요소가 발견되지 크게하면 성능을 향상시킬 것입니다.

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

return요소를 찾을 수 없는 경우가 없으며 undefined가장 가까운 요소를 찾을 수 없을 때 효과적으로 반환 됩니다.

자세한 내용은 https://developer.mozilla.org/en-US/docs/Web/API/Element/closest를 참조하십시오.


4
페이지 하단에이 답변이있는 이유는 무엇입니까? 맨 위에 있어야합니다. 고마워요
줄리앙 르 Coupanec

가장 가까운 것은 jQuery에 있지만 OP는 jQuery가 없다고 말합니다.
스티브는 moretz

@stevemoretz. 가장 가까운 이제 자바 스크립트 기본입니다
루이스 Eggleton

@LouiseEggleton 그래 그것은이다 죄송합니다
스티브 moretz

그것이 최고의 답변입니다!
ChosenUser

22

다음은 jQuery없이 태그 이름으로 가장 가까운 요소를 가져 오는 방법입니다.

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
나는 이것이 효과가있을 것이라고 믿지 않는다. DOM 트리 만 확인합니다. TH-> thead-> 테이블이 결코 형제 고려하지
hunterc

2
질문에 해당 사례를 명시해야합니다.
Joon

2
보기. 이 함수는 parentNode를 순회하여 제공된 태그를 사용하는 가장 가까운 상위 (확장자 포함)를 찾습니다. 이것은 문서 트리의 "아래"가 아니라 "위"로만 이동합니다. 일반 사용자는 "가장 가까운"노드를 가장 가까운 형제로 볼 수 있습니다. 그는 필요한 용어를 모르고 있습니다.

1
@Jhawins에게 공정하게 가장 가까운 정의는 jQuery 용어가 가장 가까운 것입니다. 이것은 jQuery 질문이 아닙니다. jQuery가 가장 가까운 조상을 의미한다고 결정한 이유를 증명할 수는 없지만 더 합리적인 정의는 부모, 이전 형제, 다음 형제 등 가장 가까운 요소가 될 것입니다. 대상 요소에 "가장 가까운"것으로 발견되는 요소는 무엇이든간에 말입니다.
ryandlf 2014

1
@ryandlf하지만 부모와 형제가 같은 "거리"에 있다면 어떨까요? jQuery의 정의는 최대 하나의 일치를 반환한다는 점에서 분명합니다.
mtone 2014

9

이를 수행하는 표준화 된 함수가 있습니다 : Element.closest . IE11을 제외한 대부분의 브라우저가이를 지원합니다 ( caniuse.com의 세부 사항 ). MDN 워드 프로세서는 또한 이전 버전의 브라우저를 대상으로 할 경우에 polyfill을 포함한다.

tbody주어진 가장 가까운 부모 를 찾으려면 th다음을 수행하십시오.

th.closest('tbody');

직접 함수를 작성하려는 경우-여기에 내가 생각 해낸 것이 있습니다.

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

태그 이름으로 가장 가까운 부모를 찾으려면 다음과 같이 사용할 수 있습니다.

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

이 솔루션은 HTML 5 사양의 최신 기능 중 일부를 사용하며 이전 / 호환되지 않는 브라우저 (읽기 : Internet Explorer)에서이를 사용하려면 폴리 필이 필요합니다.

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

항상 첫 번째 테이블로 이동합니다. 가장 가까운 테이블이 아닙니다 ..이 링크를 참조하십시오 jsfiddle.net/guuy5kof
Balachandran

좋은 캐치! 고정 여기를 참조 jsfiddle.net/c2pqc2x0 : 보스처럼 upvote에에게 나를 기쁘게
매튜 제임스 데이비스

ya i ill do ... 바이올린 결과를 확인 했습니까? 오류가 표시됩니다. ..matches undefined
Balachandran

나를 위해 잘 작동합니다. 어떤 브라우저에서 작업하고 있습니까? 이것은 이전 버전의 브라우저에서 지원되지 않습니다
매튜 제임스 데이비스에게

헤이 당신이 무슨 말을하겠습니까
-Matthew James Davis

3

@SalmanPK 답변을 확장하려면

마우스 오버와 같은 이벤트로 작업 할 때 유용한 선택기로 노드를 사용할 수 있습니다.

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

내가 사용하는 간단한 기능은 다음과 같습니다.

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

요약:

특정 조상을 찾기 위해 다음을 사용할 수 있습니다.

Element.closest();

이 함수는 CSS 선택기 문자열을 인수로 사용합니다. 그런 다음 인수에 전달 된 CSS 선택자와 일치하는 현재 요소 (또는 요소 자체)의 가장 가까운 조상을 반환합니다. 조상이 없으면 반환 null됩니다.

예:

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

클래스, ID, 데이터 속성 또는 태그가 포함 된 트리에서 가장 가까운 DOM 요소를 가져옵니다. 요소 자체를 포함합니다. IE6에서 다시 지원됩니다.

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');

firstChar모든 IF조건 대신에 스위치를 사용하지 않는 이유는 무엇 입니까?
Rafael Herscovici

왜 가려진 for루프를 사용합니까?
Rafael Herscovici

1

가장 가까운 요소 childNode를 찾습니다.

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

여기.

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

나무 아래에있는 형제 자매 만 찾습니다. previousSibling 을 사용 하여 다른 길로 이동하거나 변수를 사용하여 양방향을 탐색하고 먼저 찾은 것을 반환하십시오. 일반적인 아이디어를 얻었지만 형제가 일치하지 않는 경우 parentNodes 또는 자식을 통과하려면 jQuery를 사용할 수 있습니다. 그 시점에서 쉽게 가치가 있습니다.


0

파티에 조금 늦었지만 내가 지나가는 동안 매우 유사한 질문에 답하기 만하면 여기에 내 솔루션을 드롭합니다. JQuery closest()접근 방식 이라고 말할 수 있지만 JavaScript에서는 매우 좋습니다.

pollyfill이 필요하지 않으며 이전 브라우저이며 IE (:-)) 친화적입니다 : https://stackoverflow.com/a/48726873/2816279


-4

가장 가까운 jquery로 잡는 가장 쉬운 코드는 다음과 같습니다.

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

고맙습니다.

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