HTML은 부모와 자식관계의 구조를 갖는다.
<html>
<body>
<fieldset>
<input type="button" />
</fieldset>
</body>
</html>
위와 같은 HTML 코드가 있다면,
input 태그는 fieldset 태그에 감싸져 있고,
fieldset 태그는 body 태그에 감싸져 있고,
body 태그는 html 태그에 감싸져 있다.
여기에 자바스크립트를 이용하여 input, fieldset, body, html 각각 이벤트 핸들러를 설정했다고 가정해본다.
input 태그의 버튼을 클릭했을 때,
html 이벤트핸들러 => body 이벤트핸들러 => fieldset 이벤트핸들러 => input 이벤트핸들러
순 으로 실행이 되는 것이 캡처링이다.
반대로,
가장 내부에 있고 안쪽에 있는 구체적인 엘리먼트에 대한 이벤트부터 발생하여 상위 태그들로 나아가면서 실행되는 것이 버블링이다.
1. 캡처링
위에서 간략하게 설명한 것 처럼,
부모에 설치되어있는 이벤트부터 자식의 방향으로 나아가면서 이벤트가 실행되는 것이 캡처링이라고 할 수 있다.
코드로 보면,
<html>
~
<style>
html{border:5px solid pink;padding:30px;}
body{border:5px solid gold;padding:30px;}
fieldset{border:5px solid blue;padding:30px;}
input{border:5px solid black;padding:30px;}
</style>
~
먼저 css로 html/body/fieldset/input 태그에 디자인을 입혔다.
여기서 fieldset이란 그냥 연관된 요소를 하나의 set으로 묶는다 라는 정도로만 이해하면 되겠다.
<body>
<fieldset>
<input type="button" id='a' value="button" />
</fieldset>
<script>
function handler(event){
var test = ['capturing', 'a', 'bubbling'];
console.log(event.target.nodeName, this.nodeName, test[event.eventPhase-1]);
}
document.getElementById('a').addEventListener('click', handler, true)
document.querySelector('fieldset').addEventListener('click', handler, true)
document.querySelector('body').addEventListener('click', handler, true)
document.querySelector('html').addEventListener('click', handler, true)
</script>
</body>
</html>
위와 같이 코드를 짰다.
HTML 부분들을 보면 id가 a인 button 타입의 input 태그가 있고 부모로 fieldset => body => html 태그가 된다.
자바스크립트 부분에서
a라는 id의 엘리먼트에 addListener를 설치했고,
fieldset, body, html 태그에 addListener를 설치했다.
여기서 querySelector의 개념은,
태그, 클래스, 아이디와 같은 DOM을 찾을 때 사용한다 라는 정도만 이해하면 되겠다.
(getElement(s)By~ 와 같은 기능)
addEventListener 내용은 click 이벤트 시 handler 라는 메소드가 호출되는 것이다.
그리고 3번째 인자는 캡처링의 유무에 관한 값이다.
true라면 캡처링을 false라면 버블링을 의미하며 인자를 사용하지 않으면 default값이 false가 되어 버블링을 의미한다.
handler 함수를 확인해보면,
test 라는 변수에 capturing, a, bubbling 이라는 문자열을 배열 형태로 만들었다.
그리고 event.target의 nodeName과 this의 nodeName 그리고 배열값을 조작한 어떠한 값까지 3가지 형태의 값을 콘솔창에 출력하도록 했다.
event.target은 이벤트가 발생한 대상이라고 이해하면 된다.
따라서 console.log의 첫 번째 인자는 "이벤트가 발생한 대상의 노드이름" 이 된다.
두 번째 this는 자기자신 이라는 정도로만 이해하면 되겠다. (php에서 자세한 설명을 했지만 따로 정리할예정)
따라서 두 번째 인자는 "자기 자신의 노드이름" 이 된다.
세 번째 test[event.Phase-1] 에서 event.Phase는 이벤트 흐름의 실행단계를 보여주는 상수를 의미한다.
캡처링이면 1, 버블링이면 3, target이 된다면 2 라는 상수를 갖는다.
결과로 확인해본다.
input 태그의 버튼을 클릭한 콘솔창이다.
eventListner의 3번째 인자가 true로써 캡처링 방식으로 설정되어있기 때문에 가장 상위에 있는 부모로부터 이벤트가 실행된다.
두 번째 인자인 this.nodeName 값을 보면 html => body => fieldset => input 순으로 나아가는 것이 확인가능하다.
그리고 첫 번째 인자는 event.target으로 이벤트가 발생한 button 타입의 input 태그를 의미하므로 전부 동일한 값이다.
세 번쨰 인자는 이벤트 흐름의 실행단계를 보여주는 상수에서 -1 을 연산한 상수의 배열 값이다.
이벤트는 input 에서 실행되었지만 캡처링 방식이므로 html, body, fieldset은 모두 1의 상수를 갖는다.
따라서 1-1=0 이므로 test[0] 의 값인 capturing 이 되며,
input 에서는 target phase 즉, 이벤트 주체인 본인이 되므로 2라는 상수를 갖게되어 test[1] 인 a 가 된다.
코드를 살짝 바꿔 하나만 더 확인해본다.
document.querySelector('body').addEventListener('click', handler)
document.querySelector('html').addEventListener('click', handler)
body 와 html 부분의 3번째 인자를 제거했다.
즉, 버블링을 의미한다.
이번엔 body 영역을 "클릭" 한 결과이다.
버블링은 자식에서부터 부모의 방향으로 나아가며 이벤트가 발생이 된다.
콘솔 창에서 확인할 수 있듯이 body => html 이다.
event.target 은 body가 되므로 console창의 첫 번째 값은 BODY가 되며
body 부터 시작되어 부모로 나아가는 것이므로 input 과 fieldset은 이벤트가 발생되지 않는다.
this는 자기자신을 의미하므로 body 와 html 의 값을 갖는다.
세 번째 인자에서 html은 버블링 phase가 되므로 3의 값을 가져 test[3-1] = test[2] 인 bubbling 이 된다.
만약 캡처링 방식이든 버블링 방식이든 특정 노드까지만 이벤트가 전파되는 것을 설정하려면 어떻게 해야되나?
stopPropagation() 이라는 메소드를 사용하면 된다.
코드를 이것도 조금만 바꿔본다.
<script>
function handler(event){
var test = ['capturing', 'a', 'bubbling'];
console.log(event.target.nodeName, this.nodeName, test[event.eventPhase-1]);
}
function stophandler(event){
var test = ['capturing', 'a', 'bubbling'];
console.log(event.target.nodeName, this.nodeName, test[event.eventPhase-1]);
event.stopPropagation();
}
document.getElementById('a').addEventListener('click', handler)
document.querySelector('fieldset').addEventListener('click', handler)
document.querySelector('body').addEventListener('click', stophandler)
document.querySelector('html').addEventListener('click', handler)
</script>
stophandler라는 함수를 만들고 마지막 줄에 stopPropagation() 을 추가하였고,
각 이벤트들은 버블링 방식으로 만들었으며 body 태그에서 stophandler 의 이벤트핸들러를 호출하게 했다.
버튼 클릭 시 body 에서 html로 넘어가지 않고 이벤트가 끝나버렸다.
이렇게 stopPropagation 메소드로 원하는 위치까지 이벤트를 실행시킬 수 있다.
'Javascript' 카테고리의 다른 글
20. 문서로드 (0) | 2021.10.04 |
---|---|
19. 이벤트 기본동작 취소 (0) | 2021.09.29 |
17. 이벤트 (0) | 2021.09.27 |
16. Node 종류 API (0) | 2021.09.18 |
15. Node 관계 API (0) | 2021.09.17 |