<style>
form * {
margin: 10px;
border: 1px solid blue;
}
</style>
<form onclick="alert('form')">FORM
<div onclick="alert('div')">DIV
<p onclick="alert('p')">P</p>
</div>
</form>
FORM
P
위 코드를 실행하면 3번의 alert이 뜬다.
최하위 요소부터 p=>div=>form 이렇게. 이 프로세스를 바로 "Bubbling" 이라고 한다.
이벤트가 거품처럼 밑에서부터 부모를 향해 "bubble"하기 때문이다.
이때 "거의" 모든 이벤트가 버블링 된다는 것이다. 여기서 포인트는 "almost" 이다.
예를 들어 focus이벤트는 버블링되지 않는다. 하지만 이는 예외이고 대부분이 버블링된다.
.target
속성을 통하여 실제로 발생한 위치에 대한 세보 정보를 얻을 수 있다.즉, 위의 코드에서 보면
this
값은 계속하여form
tagName이 나오고 event.target의 tagName은 해당 요소가 정확히 찍혀 나온다.
propagation
사전적 의미로 "전파"를 뜻하며 사용법은 event.stopPropagation
이다.<body onclick="alert(`the bubbling doesn't reach here`)">
<button onclick="event.stopPropagation()">Click me</button>
</body>
요소에 단일 이벤트에 대한 여러 이벤트 핸들러가 있는 경우
그 중 하나가 버블링을 중지하더라도 다른 하나는 계속 실행된다.
즉, event.stopPropagation()
를 써도 해당 이벤트 핸들러만 멈추고 다른 이벤트들은 계속하여 버블링이 진행되지만 event.stopImmediatePropagation()
를 사용하면 이 이후에 핸들러들은 실행되지 않는다.
하지만 우리가 일반적으로는 bubbling을 막을 필요는 거의 없을 것이다.
예를 들어 우리가 nested menu를 만들었다 치자. 각 요소마다.stopPropagation
을 걸어버리면 메뉴는 어디상 작동하지 않는다.
또한 분석을 위하여 window에 사용자 "클릭" 이벤트를 걸어둬도 그것역시 작동하지 않게 된다.
capture
속성값만 추가해주면 된다.<body>
<div class="one">
<div class="two">
<div class="three">
</div>
</div>
</div>
</body>
var divs = document.querySelectorAll('div');
divs.forEach(function(div) {
div.addEventListener('click', logEvent, {
capture: true // default 값은 false
});
});
function logEvent(event) {
console.log(event.currentTarget.className);
}
사실상 위 개념들을 delegation을 위해 배웠다고해도 무방하다.
delegation은 사전적 의미로 위임을 뜻한다.
즉, 하위요소에서 이벤트 설정을 일일이 하지 않고 상위요소로 "위임"한다. 이렇게 되면 이벤트 설정을 상위요소에서 1번만 해주면 된다는 아주 미친 효율을 갖고있다.
<h1>오늘의 할 일</h1>
<ul class="itemList">
<li>
<input type="checkbox" id="item1">
<label for="item1">이벤트 버블링 학습</label>
</li>
<li>
<input type="checkbox" id="item2">
<label for="item2">이벤트 캡쳐 학습</label>
</li>
</ul>
// 하위요소에 일일이 이벤트를 넣어주는 코드
var inputs = document.querySelectorAll('input');
inputs.forEach(function(input) {
input.addEventListener('click', function(event) {
alert('clicked');
});
});
// 새 리스트 아이템을 추가하는 코드
var itemList = document.querySelector('.itemList');
var li = document.createElement('li');
var input = document.createElement('input');
var label = document.createElement('label');
var labelText = document.createTextNode('이벤트 위임 학습');
input.setAttribute('type', 'checkbox');
input.setAttribute('id', 'item3');
label.setAttribute('for', 'item3');
label.appendChild(labelText);
li.appendChild(input);
li.appendChild(label);
itemList.appendChild(li);
// delegation을 통하여 상위요소에 1번 이벤트를 넣어주는 코드
var itemList = document.querySelector('.itemList');
itemList.addEventListener('click', function(event) {
alert('clicked');
});