본문 바로가기
Javascript

closest() 실용적으로 사용하기

by F.E.D 2021. 6. 29.

javascript를 통해서 가장 가까운 요소를 찾는 방법 중에 closest()라는 메서드가 있습니다.

DOM 노드의 부모를 찾는데 어려움을 겪은 적이 있나요?

<div data-id="normal">
  <button>Click</button>
</div>

data-id 값을 한번 가져와볼까요?

const button = document.querySelector("button");

button.addEventListener("click", (event) => {
  console.log(event.target.parentNode.dataset.id);
  // normal
});

이런 케이스의 경우에는 parentNode API로도 충분합니다. 

하지만 HTML 구조가 조금 더 중첩이 되면 어떨까요? 

반복문으로 parentNode를 계속 돌면서 찾는 것은 매우 비효율적일 수도 있습니다.

 

물론 closest()가 적용이 안되는 환경에서는 while문과 같은 반복문을 사용해야합니다.

function getParentNode(el, tagName) {
  while (el && el.parentNode) {
    el = el.parentNode;
    
    if (el && el.tagName == tagName.toUpperCase()) {
      return el;
    }
  }
  
  return null;
}

위 내용을 보시면 계속해서 el 자체가 존재한다면 el에 다시 그 부모를 할당하는 식으로 반복해서 해당 태그를 리턴해주는 함수입니다.

console.log(getParentNode(button, 'div').dataset.id);

같은 상황에서 div태그 내에 많은 HTML 구조가 포함되고 있을 때 위와 같이 사용하시면 됩니다.

하지만 div태그가 반복된다면 어떨까요? 완벽하지 않네요.

 

하위 브라우저 호환성까지 포함되는 jquery에서는 다음과 같이 사용할 수도 있습니다.

$("button").closest("[data-id='normal']")

하지만 closest()만 사용하자고 jquery를 임포트하는 것은 매우 비효율적이죠.

console.log(button.closest("div"));

하지만 이렇게 자바스크립트에서 사용할 수 있습니다.

 // 만약에 드롭다운과 같은 메뉴에서 바깥쪽을 클릭할 때의 예
  if (!evt.target.closest(".menu-dropdown")) {
    menu.classList.add("is-hidden");
    navigation.classList.remove("is-expanded");
  }

만약 가까운 요소에 menu-dropdown이 없다면 닫아버리는 것은 쉽게 위와같이 구현가능합니다.

 

function TableView({ users }) {
  function handleClick(evt) {
    var userId = evt.currentTarget
    .closest("[data-userid]")
    .getAttribute("data-userid");


    // do something with `userId`
  }


  return (
    <table>
      {users.map((user) => (
        <tr key={user.id} data-userid={user.id}>
          <td>{user.name}</td>
          <td>{user.email}</td>
          <td>
            <button onClick={handleClick}>Edit</button>
          </td>
        </tr>
      ))}
    </table>
  );
}

리액트에서는 위와 같이 사용될 수 있습니다. 

가장 가까운 요소의 user.id를 가져올 수 있겠지요.

 

 

See the Pen Modal Example with `Element.closest` by YoungMinKim (@oinochoe) on CodePen.

위와 같은 예시로 모달을 닫을 수도 있습니다. esc 눌렀을 때 닫히는 것은 보너스 기능으로 넣어보았습니다.

 

closest() DOM API는 94% 이상을 지원하지만 여전히 IE는 내년에 사라지더라도 존재하기 때문에 IE를 위해서는 여전히 jquery의 closest()를 사용해야 합니다.

 

감사합니다.

 

출처 : https://css-tricks.com/practical-use-cases-for-javascripts-closest-method/

댓글