이벤트 버블링은 특정 화면 요소에서 이벤트가 발생했을 때 해당 이벤트가 더 상위의 화면 요소들로 전달되어 가는 특성을 의미합니다.
...
<div class="one">
one
<div class="two">
two
<div class="three">
three
</div>
</div>
</div>
<script>
let divs = document.querySelectorAll('div');
divs.forEach(function (div) {
div.addEventListener('click', logEvent);
});
function logEvent(event) {
console.log(event.currentTarget.className);
}
</script>
실행결과
one 클릭 시 -> one
two 클릭 시 -> two , one
three 클릭 시 -> three , two , one
이벤트 버블링의 예시로 브라우저의 기본적인 이벤트 감지 방식이기도 하다.
각각의 div 태그에 이벤트 리스너를 등록한 이유는 이벤트가 전파되는지를 확인하기 위해서이다.
two ,three 클릭시 아래에서 위로 각각의 등록한 이벤트가 호출되는것을 확인할 수 있다. (만약 이벤트 리스너를 등록하지 않았다면 확인할 수는 없음)
이벤트 버블링과 반대 방향으로 전파되는 이벤트 방식이다.
// 편의상 html태그는 위와 동일합니다.
<script>
let divs = document.querySelectorAll('div');
divs.forEach(function (div) {
div.addEventListener('click', logEvent, {
// default는 false임
capture: true
});
});
function logEvent(event) {
console.log(event.currentTarget.className);
}
</script>
실행결과
one 클릭 시 -> one
two 클릭 시 -> one , two
three 클릭 시 -> one , two , three
정의대로 이벤트가 최상위부터(body태그) 이벤트를 감지하며 내려감을 알 수 있습니다.
이벤트가 전파되는것을 막는 api입니다.
이벤트 버블링
-> 클릭한 요소의 이벤트만 발생시키고 상위 요소로 이벤트를 전달하는 것을 방해합니다.
<div class="one">
one
<div class="two">
two
<div class="three">
three
</div>
</div>
</div>
<script>
let divs = document.querySelectorAll('div');
divs.forEach(function (div) {
div.addEventListener('click', logEvent);
});
function logEvent(event) {
console.log(event.currentTarget.className);
event.stopPropagation()
}
</script>
<실행결과>
one 클릭 시 -> one
two 클릭 시 -> two
three 클릭 시 -> three
이벤트 캡쳐링
-> 클릭한 요소의 최상위 요소의 이벤트만 동작시키고 하위 요소들로 이벤트를 전달하지 않습니다.
<div class="one">
one
<div class="two">
two
<div class="three">
three
</div>
</div>
</div>
let divs = document.querySelectorAll('div');
divs.forEach(function (div) {
div.addEventListener('click', logEvent, {
// default는 false임
capture: true
});
});
function logEvent(event) {
console.log(event.currentTarget.className);
event.stopPropagation()
}
<실행결과>
one 클릭 시 -> one
two 클릭 시 -> one
three 클릭 시 -> one
하위요소에서 이벤트를 붙이기 않고 상위 요소에서 하위요소의 이벤트를 제어하는 방식을 의미한다.
그럼 이러한 방식이 왜 필요한가?
<h1>오늘의 할 일</h1>
<ul class="itemList">
<li>
<input type="checkbox" id="item1">
<label for="item1">이벤트 버블링 학습</label>
</li>
<li>
<input type="checkbox" id="item2">
<label for="item2">이벤트 캡쳐 학습</label>
</li>
</ul>
<script>
let inputs = document.querySelectorAll('input');
inputs.forEach(function (input) {
input.addEventListener('click', function (event) {
alert('clicked');
});
});
</script>
예를 들어 리스트가 동적으로 추가되는 html태그의 경우 생성할때마다 일일이 이벤트 리스너를 등록해야하는 번거로움이 생긴다.
이에 대한 해결책으로 리스트 태그들의 부모태그에 이벤트 리스너를 등록하게 된다면 이벤트 버블링에 의해서 리스트에 발생한 이벤트를 부모태그에서 감지하게 된다.
itemList 태그에서 리스트에서 발생한 이벤트를 감지
<script>
let itemList = document.querySelector('.itemList');
itemList.addEventListener('click', function (event) {
alert('clicked');
});
</script>
정리하자면 브라우저의 이벤트 작동방식은 기본적으로는 이벤트 버블링 형태로 동작한다. 이와 반대되는 개념으로는 이벤트 캡쳐링 방식이 있고 약간의 꼼수를 사용한다면 event.stopPropagation()함수를 사용할 수 있을것 같다. 위 api는 이벤트 버블링의 경우 클릭한 요소의 이벤트만 동작시키고 해당 이벤트를 위로 전파한다. 이벤트 캡쳐링의 경우 최상위 요소의 이벤트만 동작시킨다. 마지막으로 이벤트 위임은 이벤트 버블링 방식을 활용하여 최 상단에서 하위 요소의 이벤트를 감지하여 동적으로 생성하는 리스트등의 예에서 활용해 볼 수 있을 것 같다.