JavaScript 부모요소와 자식요소에 같은 이벤트를 바인딩했을 때


다음 예제 코드를 보자.

HTML
1
2
3
4
<div class="parent">
<button class="child">Click me to check</button>
</div>
<input type="checkbox" id="checkbox">
JavaScript
1
2
3
4
5
6
$('.parent').on('click', function() {
$('#checkbox').prop('checked', false);
});
$('.child').on('click', function() {
$('#checkbox').prop('checked', true);
});

.parent라는 녀석이 .child라는 버튼을 가지고 있으며 부모와 자식 요소에는 같은 click 이벤트가 바인딩 되어있다.
.child는 체크박스에 체크를 하고, .parent는 체크를 해제한다.

Result에 표시된 버튼은 .child요소 이므로 클릭할 경우에 .child에 걸린 click 이벤트가 동작하여 체크박스에 체크가 되어야 할 것이다.
하지만 실제로 버튼을 누를 경우 아무 일도 일어나지 않는다.

Event Bubbling

자바스크립트에는 Event Bubbling이라는 개념이 있다. 이것은 한 자식 요소에서 이벤트가 발생했을 때 부모요소에 이벤트를 전파하는 것을 말한다.
위의 코드에서 버튼을 누를 경우 체크가 되지 않는 이유도 바로 Event Bubbling 때문이다.
우리는 분명히 .child요소를 클릭했기 때문에 checked 상태가 되어야 마땅하지만 Event Bubbling으로 인해 부모 요소로 이벤트가 전파되었고, 그 때문에 .parent에 바인딩 된 체크 해제 이벤트가 동작하면서 결과적으로 체크가 되지 않은 상태가 된 것이다. 즉, Event Bubbling은 자식 요소의 이벤트가 먼저 동작하고 그 다음에 부모 요소의 이벤트가 동작한다.

내가 극단적인 예제 코드를 짜서 와닿지 않을지도 모르지만 실제로는 Event Bubbling을 막아야할 일이 종종 있다.
그렇다면 Event Bubbling을 막기 위해서는 어떻게 해야할까?

e.stopPropagation();

방법은 간단하다. 기존 코드에 단 한 줄만 추가하면 된다.

JavaScript
1
2
3
4
5
6
7
$('.parent').on('click', function() {
$('#checkbox').prop('checked', false);
});
$('.child').on('click', function(e) {
e.stopPropagation();
$('#checkbox').prop('checked', true);
});

이렇게 .child요소에 e.stopPropagation(); 이라는 코드만 추가하면 말끔하게 해결된다.
e.stopPropagation();은 자식 요소에서 부모 요소로 Event Bubbling되는 것을 막아준다.


그 외

사실 이벤트는 부모에서 자식으로 전달되게 할 수도 있으며 이벤트를 차단하는 방법도 더 있다. 하지만 아직 이 부분에 대해서 공부가 되지 않았기에 포스팅은 나중으로 미룬다.


참고링크