HTML에서 중첩된 3개의 태그가 있을 경우, 자신인 p 태그에서만 이벤트가 실행되는 것이 아닌 div, form 태그까지 이벤트가 발생하며 이를 이벤트 흐름이라고 한다. 이러한 현상이 발생하는 이유는 HTML이 계층적 구조로 되어있기 때문이다.
자식 요소에서 발생한 이벤트가 바깥 부모 요소로 전파되는 것이다.
<form onclick="alert('I am Form')">FORM
<div onClick="alert('I am Div')">DIV
<p onclick="alert('I am P')">P</p>
</div>
</form>
p태그를 클릭하고, 화면에 나타나는 경고창의 순서는 이렇다.
1. I am P
2. I am Div
3. I am Form
자신인 p > div > form 순으로, 즉 자식에서 부모로부터 이벤트가 전파되는 것을 알 수 있다.
자식 요소에서 발생한 이벤트가 부모 요소부터 시작하여 안쪽 자식 요소까지 도달하는 것이다.
<form onclick="alert('I am Form')">FORM
<div onClick="alert('I am Div')">DIV
<p onclick="alert('I am P')">P</p>
</div>
</form>
p태그를 클릭해보자.
1. I am Form
2. I am Div
3. I am P
이처럼 캡쳐링은 자식태그인 p태그를 클릭해도 부모 요소부터 시작해서 자식 요소까지 도달하는 것이다.
1. 캡쳐링 단계
2. 타깃 단계
3. 버블링 단계
<form onclick="alert('I am Form')">FORM
<div onClick="alert('I am Div')">DIV
<p onclick="alert('I am P')">P</p>
</div>
</form>
위의 과정을 참고해서 코드를 실행하여 이벤트가 전파되는 순서를 보자.
1. p태그를 클릭하면 이벤트가 최상위 조상에서 시작해 아래로 전파 (캡쳐링 단계)
2. 이벤트가 타깃 요소(p태그)에 도착해 리스너를 실행한다 (타깃 단계)
3. p태그에서 다시 상위인 div, form 태그로 이벤트를 전파한다 (버블링 단계)
<form onclick="alert('I am Form')">FORM
<div onClick="alert('I am Div')">DIV
<p onclick="alert('I am P')">P</p>
</div>
</form>
🫧 p태그를 클릭할 시 뜨는 경고창의 순서
1. I am Form
캡쳐링 단계 (1-3)
2. I am Div
3. I am P
4. I am P
타깃 단계 (4), 버블링 단계 (4-6)
5. I am Div
6. I am Form
🫧 div 태그를 클릭할 시 뜨는 경고창의 순서
1. I am Form
캡쳐링 단계 (1-2)
2. I am Div
3. I am Div
타깃 단계 (3), 버블링 단계 (3,4)
4. I am Form
브라우저는 캡쳐링-버블링으로 이벤트가 동작한다. 하지만 자식태그의 이벤트만 실행하고, 부모태그의 이벤트는 실행하기 싫을 때 어떻게 해야할까?
stopPropagation()은 상위 엘리먼트들로의 이벤트 전파를 중단시킨다.
<form onclick="alert('I am Form')">FORM
<div onClick="alert('I am Div')">DIV
<p onclick={function(e){
e.stopPropagation();
alert("I am P")
}}>P</p>
</div>
</form>
p태그 클릭 시, e.stopPropagation()로 인해서 부모태그의 alert는 안 뜨고 p태그의 alert만 나타난다.
e.preventDefault는 고유의 동작을 중지시킨다.
예를들어, 페이지를 이동시키는 a와 form안의 input을 제출시키는 submit은 고유의 동작이 있는데 e.preventDefault를 쓰면 a 안에 있는 href 속성과 submit의 제출 동작이 무효화 된다.