자바스크립트 - 이벤트 버블링 / 캡쳐링 / 이벤트 위임 / 이벤트 방지
각 요소 별로 click 타입에 이벤트 핸들러 등록 했을 때
한 요소에 이벤트가 발생했을 때 해당 요소에 할당된 이벤트 핸들러가 동작하고 끝나는게 아니라
부모 요소에 걸쳐 최상위(window) 요소까지 (같은 타입에 한해서) 이벤트가 모두 동작함 = 이벤트 버블링
뭔가 이런 느낌의 .. 수면으로 갈수록 bubble 이 커지는 = 이벤트가 적용되는 범위가 넓어진다
event.target 메서드로 확인해보면
첫번째 item 을 선택해서 item-list-content 에 걸쳐 click 이벤트가 동작하더라도
각 event 객체의 target 프로퍼티는 click이 일어난 첫번째 item 임
-> 부모 요소의 핸들러들이 최초의 이벤트가 일어난 위치를 정확히 파악할 수 있음
event.currentTarget 메서드로 확인해보면
실제로 이벤트 핸들러가 동작하는 요소가 출력됨
event.stopPropagation()
버블링을 막는 메서드
가급적 사용 지양
모든 부모 요소의 입장에서 해당 영역만큼의 이벤트가 발생하는 범위가 사라지게 됨
document, body 수준에서 이벤트 발생시켜야 할 때 해당하는 범위에서만 원하는 이벤트 결과 얻지 못함
이벤트 흐름 순서 : 이벤트 발생 시 브라우저는 어떤 요소에서 이벤트가 발생했는지 모르기때문에 최상단 요소에서부터 타깃까지 캡쳐링 단계를 통해 타깃 요소를 찾는다
1. 캡쳐링 단계 : 이벤트가 하위 요소로 전파되는 단계
2. 타깃 단계 : 이벤트 객체의 target 프로퍼티가 되는 요소에 등록되어 있던 이벤트 핸들러가 동작하는 단계.
즉 가장 처음 이벤트 핸들러가 동작하게 되는 순간
3. 버블링 단계 : 이벤트가 상위 요소로 전파되는 단계
이 과정을 통해 각 요소에 할당된 이벤트 핸들러가 호출된다
보통 캡쳐링 단계에서 이벤트 발생 시키는 경우는 드물다
타깃 단계에서 target 요소에 등록된 이벤트 핸들러 있으면 동작하고
그 이후에 버블링 단계에서 각 부모요소에 등록된 이벤트 핸들러가 있으면 동작이 일어남
캡쳐링 단계에서 이벤트 발생시키는 방법
addEventListener 세번째 프로퍼티에 true 또는 {capture:true} 전달
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="style.css">
<title>JS with Codeit</title>
</head>
<body>
<div id="content">
<h1 id="title">오늘 할 일</h1>
<ul id="list">
<li class="item">자바스크립트 공부</li>
<li class="item">유튜브 시청</li>
<li class="item">저녁 약속</li>
<li class="item">독서</li>
</ul>
</div>
<script src="index.js"></script>
</body>
</html>
버블링을 활용한 이벤트 위임 Delegation
const list = document.querySelector('#list');
for (let item of list.children){
item.addEventListener('click', function(e) {
e.target.classList.toggle('done');
});
}
const li = document.createElement('li');
li.classList.add('item');
li.textContent = '일기 쓰기';
list.append(li);
list의 각 item 을 click 했을때 .done 클래스가 토글됨
추가된 item 요소에 이벤트 동작이 안됨
=> 이벤트 버블을 이용하기
(자식 요소에서 발생한 이벤트를 부모요소가 감지할 수 있음 &
이벤트 타겟 프로퍼티가 이벤트 발생위치를 담고있기 때문에)
부모 요소(list)에 하나의 이벤트 핸들러만 등록해줘도 모든 자식 요소의 이벤트를 다룰 수 있음
= 이벤트 위임 (자식의 이벤트를 부모에게 위임)
list.addEventListener('click', function(e) {
e.target.classList.toggle('done');
});
list 영역 내에서 item 요소 영역이 아닌 곳을 눌러도 동작이 일어나게됨
이벤트 위임을 할때는 명확히 원하는 요소에서만 의도한 동작이 일어나도록 처리해야함
list.addEventListener('click', function(e) {
if (e.target.tagName === 'LI')
e.target.classList.toggle('done');
});
tagName : 요소의 태그 이름을 대문자로 담고있는 프로퍼티
또는
list.addEventListener('click', function(e) {
if (e.target.classList.contains('item')){
e.target.classList.toggle('done');
}
});
classList.contains 메소드 : 파라미터 값이 해당 요소의 클래스 속성에 있는지 확인해서 boolean 값으로 반환
자식요소에서 버블링을 막는 stopPropagation 사용하면 이벤트 위임도 막힘
event.preventDefault()
브라우저의 기본 동작을 막는 프로퍼티 (링크 이동, 인풋박스 입력, 오른쪽클릭 방지 등)
document.addEventListener('contextmenu', function(event){
event.preventDefualt();
})
이벤트의 대상(?) -> text, link, input 등 다른 요소가 올 수 있다
이벤트 종류 -> click, keydown, ...
이벤트 핸들러 -> 이벤트 발생 시 원하는 동작
출처: 코드잇
왜 이벤트 캡쳐링과 버블링이 일어나야만 하는지 !!!
https://velog.io/@samkong/event
이벤트 캡처링과 버블링은 대체 왜 why 일어나는걸까?
캡캡캡버버버
velog.io