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.