Event
1. bubbling & capturing
- target 클릭시 브라우저는 capturing을 거치게 된다. 부모부터 해당 target 까지 내려간다.
target의 EventHandler를 호출하고 bubbling을 거치면서 부모요소들의 EventHandler까지 다 호출해버린다.
capturing단계에서 우리가 해야할 일은 거의 없다.
bubbling을 막기 위해 stopPropagation()
을 자주 사용하곤 하는데 이 방법은 위험한 방법이고 가능하면 사용하지 않도록 해야 한다. 내 이벤트만 사용하려고 하는 것이기 때문이다.
아래와 같이 조건충족시 이벤트가 호출되도록 하는 것이 더 바람직하다.
if (event.target !== event.currentTarget) {
return;
}
- 같은 요소에 등록된 다른 이벤트를 막고 싶다면
stopImmediatePropgation()
을 사용하면 된다.
먼저 등록된 이벤트는 막을 수 없고 다음 이벤트부터 막아지는데 그것은 bubbling과정에서 아래부터 순서대로 호출되기 때문이다.
하지만 stopPropagation()
과 마찬가지로 가능하면 사용하지 않도록 한다.
2. 브라우저 기본 기능 취소
preventDefault()
는 브라우저에서 기본적으로 발생하는 동작을 취소한다. 로그는 발생하지만 이벤트는 발생하지 않는다.
하지만 wheel
같은 스크롤링 관련된 이벤트는 브라우저가 이벤트를 다 기다려주면 스크롤이 굉장히 느려지니까 스크롤링 되고 있다는 것만 알려주고 동작을 하고 있는다. 즉, 브라우저의 행동을 취소할 수 없다.
addEventListener
의 option에서 passive: true
로 설정하면 preventDefault()
를 사용할 수 없다.
이 옵션을 passive: false
로 바꾸면 passive: active
가 되어 preventDafault()
호출해 브라우저를 취소할 수 있게 된다.
하지만 scrolling할때는 passive
를 변경하지말고 preventDafault()
를 호출하지 않는 것이 좋다.
3. 이벤트 위임(Event Delegation)
- 부모요소는 자식요소에서 어떤 이벤트가 발생하던 모든 이벤트를 다 들을 수 있다.
const lis = document.querySelectorAll('li');
lis.forEach(li => {
li.addEventListener('click', () => {
li.classList.add('selected');
});
});
const ul = document.querySelector('ul');
ul.addEventListener('click', event => {
if (event.target.tagName == 'LI') {
event.target.classList.add('selected');
}
});
- 반복되어지는 클릭을 처리할때, 공통적으로 무언가 해야할때 일일히 리스너를 자식에게 추가하는 것 보다 부모에 리스너를 등록해 이벤트를 위임하는 것이 좋다.
currnetTarget과 target이라는 정보가 있기 때문에 이것을 이용하면 된다.
4. 이벤트 위임의 장점
- 동적인 엘리먼트에 대한 이벤트 처리가 수월하다. 하위 엘리먼트를 추가/제거 하기 편리하다.
- 이벤트 핸들러 관리가 쉽다. 상위 엘리먼트에서 하위 여러 엘리먼트를 관리하기 때문이다.
- 메모리 사용량이 줄어든다. 동적으로 추가되는 이벤트가 없기 때문이다.
- 상위 엘리먼트에 이벤트위임을 하기에 이벤트 핸들러가 줄어들어 메모리 누수 가능성도 줄어든다.