ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • closest() 실용적으로 사용하기
    Javascript 2021. 6. 29. 00:28

    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/

Designed by Tistory.