📖 사전지식
💬 이벤트 버블링 (Event bubbling)
- 특정 엘리먼트에 이벤트가 발생하면 해당 이벤트가 그 엘리먼트의 조상들까지 전파되는 현상
- 예시 : p에 클릭이벤트가 발생 시 부모인 div와 더 나아가 body에 있는 이벤트까지 발생
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Example</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
body
<div>
div
<p>p</p>
</div>
<script src="app.js"></script>
</body>
</html>
const $p = document.querySelector('p')
const $div = document.querySelector('div')
const $body = document.querySelector('body')
function Alert(message) {
return function() {
alert(message)
}
}
$p.addEventListener('click', Alert('p tag event'))
$div.addEventListener('click', Alert('div tag event'))
$body.addEventListener('click', Alert('body tag event'))
- 방지 방법
1. event.stopPropagation라는 API 사용한다
- 하나의 이벤트에 여러 핸들러가 있을경우 stopImmediatePropagation라는 API 사용한다
💬 이벤트 캡쳐링 (Event capturing)
- 특정 엘리먼츠에 이벤트가 발생하면 이벤트가 최상단의 부모 엘리먼트로부터 전달되어져 내려오는 현상
- 기본적으로 옵션이 false이기에 이벤트 핸들러에
{capture: true} 혹은 true
로
옵션을 변경해야 확인 가능
- 예시
const elements = document.querySelectorAll('*')
for (let elem of elements) {
elem.addEventListener('click', e => alert(`캡쳐링: ${elem.tagName}`), true)
}
- 방지 방법
1. default로 설정된 false를 바꾸지 않는다
- event.stopPropagation라는 API 사용한다
💬 버블링 + 캡쳐링 이벤트
- 총 3단계로 이벤트가 발생한다
1. 캡쳐링 단계 : window 부터 타겟 엘리먼트까지 이벤트가 아래로 전달된다.
- 타겟 단계 : 이벤트가 타겟 엘리먼트에 도달한다.
- 버블링 단계 : 이벤트가 타겟 엘리먼트로부터 부모 엘리먼트들에게로 전달된다.
- 예시
const elements = document.querySelectorAll('*')
for (let elem of elements) {
elem.addEventListener('click', e => alert(`캡쳐링: ${elem.tagName}`), true)
elem.addEventListener('click', e => alert(`버블링: ${elem.tagName}`))
}
- 주의할점 : 캡쳐링과 버블링 모두 2단계에서 타겟 엘리먼트의 이벤트를 작동시킴 (2회)
📖 이벤트 위임(Event Delegation)
💬 개념
- 캡쳐링과 버블링을 이용한 것
- 여러 엘리먼트마다 각각 이벤트 핸들러를 할당하지 않고, 공통되는 부모에 이벤트 핸들러를
할당하여 이벤트를 관리하는 방식
✏ 예시
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Example</title>
</head>
<body>
<form>
<input type="text"/>
<button type="submit">등록하기</button>
</form>
<ul></ul>
<script src="app.js"></script>
</body>
</html>
const $form = document.querySelector('form')
const $input = document.querySelector('input')
const $ul = document.querySelector('ul')
$form.addEventListener('submit', e => {
e.preventDefault()
const li = document.createElement('li')
li.innerText = $input.value
$ul.appendChild(li)
$input.value = ''
})
$ul.addEventListener('click', e => {
alert(e.target.innerText)
})
💬 이벤트 위임을 왜 해야할까?
- 같은 액션에 따라서 다른 동작을 하는 여러 버튼이 있다고 가정할 때 모든 버튼에
이벤트 리스너를 등록하는 것은 비효율적임
- 또한 동적으로 추가되거나 삭제되는 엘리먼트에 이벤트를 처리할때 매번 리스터를 추가하고
삭제하면 코드의 효율성 문제도 있고 리스너가 삭제되지않는 경우가 발생한다면 메모리 누수
가능성이 커짐
- 결론 : 코드의 효율성 + 메모리 누수 방지
💡 답변
이벤트 위임이란?
이벤트 버블링과 캡쳐링을 사용하여 여러 엘리먼트에 각각 이벤트 핸들러를 할당하지 않고
공통되는 부모에 이벤트 핸들러를 할당하여 이벤트를 관리하는 방식입니다.
해당 방식으로 관리를 하면 장점으로 코드의 효율성 증가와 메모리 누수 방지가 있습니다.
이벤트 버블링이란?
특정 엘리먼트에 이벤트가 발생하면 해당 이벤트가 그 엘리먼트의 조상들까지 전파되는 현상
이며 방지하는 방법으로는 이벤트 객체의 stopPropagation라는 함수를 사용하면됩니다.
부모에서 자식으로 이벤트 상속방법은?
이벤트 캡쳐링을 사용하면됩니다. capture라는 옵션이 있는데 기본적으로 false로 되어
있기에 이벤트 리스터 사용시 옵션 값으로 true를 주게 되면 캡쳐링 사용이 가능합니다.
이벤트 버블링 막는 방법
이벤트 객체의 stopPropagation라는 함수를 사용하면됩니다.
이벤트 버블링 활용 방법
이벤트 위임이라는 방식으로 활용하면 됩니다.
같은 액션을 사용하지만 다른 동작을하는 여러 버튼이 있다고할 때 공통된 부모에
이벤트 핸들러를 할당하고 각 버튼의 구분점을 dataset속성이나 innerText로
구분지어 경우에 따라 다른 행동을 하게끔 코드를 작성하면 코드의 효율성이 좋아집니다.