사용할 method/ function: .closest()
사용 목적: 특정 태그에 active 클래스가 추가될 경우, 해당 태그에 인접한 parent Element 에도 active class를 붙이고자 함
사이드 바를 헤더에 붙여서 디자인을 일관화 하던 작업 중,
하위의 메뉴를 선택해도 상단 메뉴가 색이 변하지 않는 현상을 발견하였다.
타이틀에 active 클래스를 추가하던 스크립트를 정리하다 보니 발생한 현상이었다.
그런데, 기존에는 event 발생 시 해당 클래스를 직접 selector로 선택했었는데,
지금은 하위 메뉴 중에 active인 (위의 이미지와 같이 선택되어 있어서 색상이 바뀌어있는) 메뉴를 인식해서
위의 타이틀 배경 색상도 바꿔야 하는 상황으로 케이스가 바뀌었다.
<li className="nav-list"> // 2. 이 클래스에서 .active 가 붙어야 한다. (...)
<div className="submenu submenu-title">
진단 수행/ 결과 조회
<div className="sidebar-icon">
<FontAwesomeIcon icon={faSearch} />
</div>
</div>
<ul className="collapse">
<li className="nav-item">
<NavLink to="/execute/plan" className="link first-item">
신규 진단 계획 실행 // 1. 예를 들어 여기서 클릭을 하게 되면
</NavLink>
</li>
<li className="nav-item">
<NavLink to="/execute/list" className="link no-border-bottom">
진단 실행 리스트
</NavLink>
</li>
</ul>
</li>
(주석의 1, 2 번 순서대로 봐 주시면 됩니다.
하위 태그가 직접 맞닿아 있지 않아 조금 껄끄러운 상황입죠...)
선택된 클래스(.link.active) 에 따른 타이틀 색상 변경(li.nav-list)이 필요한 케이스라,
.closest() 가 적합하다 판단되어 코드에 적용해 보았다.
먼저 하위 메뉴 중 하나가 선택되면 active 클래스가 추가되므로 .active querySelector를 활용하였는데,
로고 링크도 active 상태라, 1의 index인 active 하위 메뉴만 가져오도록 .item(1) 처리를 하였다.
// 클릭으로 인해 active class 가 추가된 아이템 검색
const activeClass = document.querySelectorAll('.active').item(1)
이후 클릭한 하위메뉴에서 가장 가까운 리스트 태그 & 클래스 이름이 nav-list 인 Element를 .closest() 로 선택하도록 했다.
의도된 클래스를 select 하게 되었으니, 해당 className 에 active 를 append 하게끔 코드를 작성했다.
React.useEffect(() => {
// 클릭으로 인해 active class 가 추가된 아이템 검색
const activeClass = document.querySelectorAll('.active').item(1)
// active class 에서 제일 가까운 조상 li (nav-list class) 검색
if (activeClass) {
const activeNavList = activeClass.closest('li.nav-list')
activeNavList.className = activeNavList.className + ' active'
}
})
cf) if (activeClass) 가 있는 이유는, 프로젝트 내부 메뉴 중 사이드 바에 없는 링크도 존재하기 때문입니다.
(제 프로젝트 상의 개인 설정입니다 ㅎㅎ)
ex - 설정 페이지가 있을 때, 세부 설정 버튼을 눌러 부메뉴의 부메뉴로 들어감
이럴때는 .active 로 title을 감지할 수 없기 때문에 조건문에서 거르도록 설정했습니다.
직접 맞닿아 있는 부모-자식 태그가 아니였지만, .closest()를 활용하여 active 클래스를 추가할 수 있었다.
타이틀이 원하는 색상으로 변경되었다.
추가
아래와 같이, 작성자가 활용한 내용 외의 컨디션도 여러 가지가 존재하므로
필요에 따라 일반 class / tag / parent 조건을 곁들여서 검색하시는 것도 유용할 것 같습니다.
const el = document.getElementById('div-03');
// ID가 "div-02"인 가장 가까운 조상
console.log(el.closest('#div-02')); // <div id="div-02">
// div 안에 놓인 div인 가장 가까운 조상
console.log(el.closest('div div')); // <div id="div-03">
// div면서 article을 부모로 둔 가장 가까운 조상
console.log(el.closest("article > div")); // <div id="div-01">
// div가 아닌 가장 가까운 조상
console.log(el.closest(":not(div)")); // <article>
출처
https://developer.mozilla.org/ko/docs/web/api/element/closest