이전 포스팅에서 이벤트의 전반적인 흐름에 대해 알아보았다.
[JavaScript] 이벤트 버블링(Bubbling), 이벤트 위임(Delegation)
프로젝트 진행 중 DOM API 를 활용하여 이벤트를 다룰 일이 생겼다.모든 컴포넌트에 이벤트 등록을 하던 중, 해당 방식이 매우 비효율적인 것을 알게 되었다.이 글을 통해 이벤트의 전반적인 흐름
junhee1203.tistory.com
위 글의 마지막에서 이벤트 위임을 사용할 때,
Element.closest 메소드가 유용하다고 언급하였다.
이번 글에서 해당 메소드의 정의가 무엇인지, 왜 이벤트 위임에서 유용한지 알아보겠다.
1️⃣ Element.closest 정의
closest 는 Element 객체의 메소드이다. 이때, Element는 HTML 의 요소이다.
따라서, HTML의 모든 요소에 closest 메소드 사용이 가능하다.
예시를 들어보자.
<body>
<div class="outer">
<div class="inner-1">
<p> 첫 번째 p 태그 </p>
<p> 두 번째 p 태그 </p>
</div>
<div class="inner-2">
<span> span 태그 </span>
</div>
<div class="inner-3">
<div class="inner-4">
<button> 버튼 </button>
</div>
</div>
</div>
</body>
// closest.js
const $firstDiv = document.querySelector('.inner-1')
const $span = document.querySelector('span')
const $button = document.querySelector('button')
$firstDiv.closest('.outer')
$span.closest('p')
$button.closest('span')
다음과 같이 querySelector 를 이용하여 html 안에 요소, 즉 Element를 가져온다.
closest 는 Element 객체의 메소드이므로 위와 같이 사용할 수 있게 된다.
또한, closest 는 querySelector와 마찬가지로 선택자를 인자로 받는다.
그렇다면, 이제 closest 메소드의 의미를 알아보자.
closest 는 이름 그대로 close(가까운) 의 최상급 표현이다.
따라서, Element.closest('선택자') 의 정의는
선택자에 해당하는 요소 중 Element와 가장 가까운 요소를 가져와달라는 뜻이다.
예시를 들어보자.
위의 html 구조를 DOM으로 표현하였다.
// closest.js
const $firstDiv = document.querySelector('.inner-1')
const target = $firstDiv.closest('.outer')
console.log(target)
위의 정의를 토대로,
target 에는 outer 클래스에 해당하는 요소 중 $firstDiv 와 가장 가까운 요소가 할당된다.
그렇다면, 요소를 찾기 위해서 탐색을 해야 될텐데 어떠한 방식으로 탐색할까 ?
바로, Element를 기준으로 부모 요소만 탐색하게 된다.
즉, 위의 예시에서는 $firstDiv의 부모 요소를 탐색하고,
부모 요소 중 outer 클래스를 가진 요소가 여러 개라면
그 중 가장 $fistDiv와 가까운 부모를 target에 할당하게 된다.
위 과정을 도식화 해보자
아직 감이 오지 않는다면 다른 예시를 들어보겠다.
// closest.js
const $span = document.querySelector('span')
const target = $span.closest('div')
console.log(target)
target에 무엇이 할당될지, 위의 closest 과정을 도식화 해보자
div에 해당하는 요소는 현재 DOM에서 5개나 있다.
그 중에서 span의 부모이면서 가장 가까운 inner-2 div가 target에 할당된 것이다.
이번에는 span 요소에서 closest를 통해 innder-1 div를 찾는다고 가정하자.
현재 DOM 구조가 위와 같을 때, 찾을 수 있을까 ?
정답은, closest를 사용해서는 찾을 수 없다.
그 이유는 이미 위의 closest 탐색 방법에 나와 있다.
closest는 부모를 탐색하기에 inner-1 div 는 span의 부모가 아니므로 찾을 수 없는 것이다.
// closest.js
const $span = document.querySelector('span')
const target = $span.closest('.inner-1')
console.log(target)
참고로 탐색을 할 때, 탐색 대상에 자기 자신도 포함된다.
아래 예시를 확인하자.
아래 예시는 span 태그 중 기준과 가장 가까운 요소를 찾는데,
마침, 기준이 되는 본인이 span 태그인 예시이다.
// closest.js
const $span = document.querySelector('span')
// 기준이 $span 이다.
const target = $span.closest('span')
console.log(target)
2️⃣ Element.closest 활용
closest 메소드는 이벤트 위임에서 유용하게 사용된다.
이벤트 위임은 무분별한 핸들러 등록을 방지하기 위해 사용되는데
상위 요소에 핸들러를 등록하다 보니, 이벤트의 대상이 되는 하위 요소를 찾는 것이 어려울 수 있다.
이때 closest 메소드를 사용하면 매우 유용하다.
바로 예시를 확인하자.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>이벤트 위임 예제</title>
<style>
.item {
border: 1px solid #ddd;
padding: 10px;
margin: 5px;
}
.delete-btn {
float: right;
}
</style>
<script defer src="closest.js"></script>
</head>
<body>
<h1>할 일 목록</h1>
<ul id="todo-list">
<li class="item">
우유 사기
<button class="delete-btn">삭제</button>
</li>
<li class="item">
책 읽기
<button class="delete-btn">삭제</button>
</li>
<li class="item">
운동하기
<button class="delete-btn">삭제</button>
</li>
</ul>
</body>
</html>
// closest.js
/* #todo-list 인 ul 에 핸들러를 등록하고 하위 요소인 button의 클릭 이벤트를 버블링으로 전달 받아
이벤트 위임으로 처리하려 한다. */
const $todoList = document.querySelector('#todo-list')
$todoList.addEventListener('click',(e)=>{
// e.target.tagName 을 통해 이벤트가 발생한 곳이 button 인지 체크한다.
if(e.target.tagName == 'BUTTON'){
// 맞다면, button에서 가장 가까운 .item 인 li를 찾고 DOM에서 삭제시킨다.
const item = e.target.closest('.item')
item.remove()
}
})
이번 글을 요약해보겠다.
- 이벤트 위임에서 Element.closest('선택자') 메소드가 유용하게 쓰인다.
- Element.closest('선택자') 의 정의는 '선택자'에 해당하는 요소 중 Element와 가장 가까운 요소를 찾는다.
- Element 객체는 HTML 요소를 뜻한다.
- closest 는 인자로 선택자를 받는다.
- 요소를 찾을 때, 내 자신과 부모 요소만 탐색한다.
'JavaScript' 카테고리의 다른 글
[JavaScript] Promise와 비동기(Asnycronous) 처리 (0) | 2024.09.14 |
---|---|
[JavaScript] drag (드래그) 관련 이벤트 전격 분석 (0) | 2024.09.10 |
[JavaScript] 이벤트 버블링(Bubbling), 이벤트 위임(Delegation) (2) | 2024.08.31 |
[JavaScript] 모듈 시스템 CommonJS vs ES6 비교 (0) | 2024.08.25 |
[JavaScript] 콜백 함수와(Callback) 비동기(Asyncronous) 처리 (0) | 2024.08.11 |