[자바스크립트] 이벤트 캡쳐링 / 이벤트 버블링
addEventListener() 웹 API는 웹 개발자들이 화면에 동적 기능을 추가하기 위해서 사용하는데,
이벤트를 등록하면서 브라우저는 이벤트를 어떻게 감지하는지에 대해 알아보자.
자바스크립트는 이벤트가 발생하면 이벤트가 발생한 노드(Event Target)를 찾기 위해 DOM 트리를 탐색을 합니다.
탐색 과정은 도큐먼트 루트, 또는 가장 바깥쪽 노드에서부터 이벤트가 트리거 된 타겟 노드까지 내려가는 탐색 방식과, 반대 방향으로 다시 올라오는 탐색 방식으로 구분합니다.
타겟 노드까지 내려가는 탐색 방식을 이벤트 캡쳐링(Event Capturing),
반대 방향으로 올라오는 탐색 방식을 이벤트 버블링(Event Bubbling) 이라고 합니다.
이벤트 전파(Event Propagation) : 이벤트가 이벤트 타겟 까지 도달하기 위해 퍼져나가는 것
JS의 이벤트 리스너 등록 및 처리는 기본적으로 버블링 과정을 통해서 이벤트가 전파됨
캡쳐링 과정으로 이벤트를 전파하고 싶은 경우 이벤트 리스너 등록시 capture 옵션을 true로 켜줌
target.addEventListener ('이벤트', 콜백함수, {capture : true});
target.addEventListener ('이벤트', 콜백함수, true);
* 원하는 화면 요소의 이벤트에 적용하고 싶은 경우
옵션을 지정하면 이벤트 캡쳐링 방식(capture : true) 으로 이벤트를 전파함 > 원하지 않을 경우 event.stopPropagation();
버블링으로 상위 요소로 이벤트를 전파하는 방식으로 구현할 때, 상위 요소에 같은 이벤트를 처리하는 이벤트 리스너가 등록되어있는 경우, 원하는 이벤트 처리와 관련이 없는 콜백 함수가 실행될 수 있음
→ 여러 개의 연달아 이어진 요소에 같은 이벤트 리스너를 적용해야 할 경우, 버블링된 상위 요소에 하나의 이벤트 리스너만 적용해 반복된 이벤트 처리를 단순화할 수 있음
* 이벤트 위임( Event Delegation)
하위 요소에 각 이벤트를 붙이지 않고 상위 요소에서 하위 요소의 이벤트들을 제어하는 방식
// var inputs = document.querySelectorAll('input');
// inputs.forEach(function(input) {
// input.addEventListener('click', function() {
// alert('clicked');
// });
// });
// 화면의 모든 input박스에 일일이 넣기보다
// 인풋박스의 상위 요소인 itmList에 이벤트 리스너를 달아놓고 하위에서 발생한 클릭 이벤트를 감지
var itemList = document.querySelector('.itemList');
itemList.addEventListener('click', function(event) {
alert('clicked');
});
이벤트 버블링 / 캡쳐링 예시
HTML
<body>
<div class = "one">
<div class= "two">
<div class ="three>
</div>
</div>
</div>
</body>
이벤트 버블링 등록
// 이벤트 등록
<button> add one item</button>
var button = document.querySelector('button');
button.addEventListener('click', addItem);
funtion addItem(evnet) {
console.log(event);
}
이벤트 버블링 / 캡쳐링
// 이벤트 버블링
var divs = document.querySelectorAll('div');
divs.forEach(function(div) {
div.addEventListener('click', logEvent);
});
function logEvent(event) {
console.log(event.currentTarget.className);
}
// three / two / one
// 이벤트 캡쳐링
var divs = document.querySelectorAll('div');
divs.forEach(function(div) {
div.addEventListener('click', logEvent, {
capture: true // default 값은 false
});
});
function logEvent(event) {
console.log(event.currentTarget.className);
}
// one / two / three
참고자료