이벤트 버블링
이란, 하위 엘리먼트에서 이벤트가 발생했을 때 그 엘리먼트로부터 시작해서 상위 요소까지 이벤트가 전달되는 방식을 말한다.코드를 통해 더 쉽게 이해해보도록 하자.
<form onclick="alert('form')">
<div onclick="alert('div')">
<p onclick="alert('p')" />
</div>
</form>
<p>
를 클릭하면 순서대로 다음과 같은 일이 벌어진다.<p>
에 할당된 onclick 핸들러가 동작<div>
에 할당된 onclick 핸들러 동작<form>
에 할당된 핸들러가 동작이벤트 캡쳐링
이란, 하위 엘리먼트에 이벤트 핸들러가 있을 때 상위 엘리먼트로부터 이벤트가 발생하기 시작해서 하위 엘리먼트까지 이벤트가 전달되는 방식이다.이벤트 버블링
이고 이벤트 캡쳐링은 자주 쓰이진 않는다. 혹시나 이벤트 캡쳐링 방식으로 코드를 실행시키려면 addEventListener()
의 마지막 인자로 { capture:true }
를 전달해주면 된다.document.querySelector('ul').addEventListener('click',()=>{ console.log('클릭') },{ capture: true });
난 그냥 원하는 화면 요소의 이벤트만 신경 쓰고 싶어요
이럴 땐 어떻게 하면 좋을까? event.stopPropagation()
웹 API를 사용하면 된다.
위 API는 해당 이벤트가 전파되는 것을 막는다.
이벤트 버블링의 경우 클릭한 요소의 이벤트만 발생시키고 상위 요소로 이벤트를 전달하는 것을 방해한다. 이벤트 캡쳐의 경우도 마찬가지로 하위 요소들로 이벤트를 전달하지 않는다.
하지만, 계층 구조가 깊은 곳에서 쓰게 된다면 원하는대로 동작하지 않을 때
어디서 문제가 발생했는지 찾기 어려울 수 있다
. 그렇다면 어떻게 구현하는게 좋을까?
이벤트 위임
은 하위 요소에 각각 이벤트를 붙이지 않고 상위 요소에서 하위 요소의 이벤트들을 제어하는 방식이다.event.target
을 이용하면 실제 어디서 이벤트가 발생했는지 알 수 있다.<div onclick="alert('div')">
<button>첫 번째</button>
<button>두 번째</button>
<button>세 번째</button>
</div>
지양 🙅: button의 개수가 매우 많아지면 메모리에도 이벤트 핸들러가 쌓이기 때문에 성능에 문제가 생길 수 있다.
const buttons = document.querySelectorAll('button');
buttons.forEach(function(button) {
button.addEventListener('click', function(event) {
alert('clicked');
});
});
이벤트 위임 🙆: 가장 상위 요소인 div 리스너를 등록하고 하위에서 발생한 이벤트를 감지한다.
const div = document.querySelector('div');
div.addEventListener('click', function(event) {
alert('clicked');
});
이벤트 위임 🙆🙆🙆: 만약 div를 클릭했을 때가 아니라 button만 클릭했을 때 동작시키고 싶다면? target
을 사용한다.
const div = document.querySelector('div');
const button = document.querySelector('button');
div.addEventListener('click', function(event) {
// event의 target이 현재 클릭한 target이 아니라면 동작시키지 않는다!
if(event.target !== event.currentTarget) {
return;
}
alert('clicked');
});
button.addEventListener('click', function(event) {
alert('clicked');
});
이번 글에서는 브라우저가 이벤트를 감지하는 방식과 우리는 이벤트를 어떻게 다뤄야 하는지에 대해 알아보았다. 아래의 이벤트 흐름 3가지를 통해 오늘의 내용을 복습해보자.