[출처 : javascript info]
이벤트 객체의 속성 중 target과 currentTarget이 있는데 target은 이벤트가 발생한 가장 안쪽 요소 를 의미한다.
currentTarget은 이벤트 핸들링을 하는 현재 요소( 핸들러가 실제로 할당된 요소)를 가르킨다.
event.target은 실제 이벤트가 시작된 '타깃'요소로 버블링이 진행되어도 변하지 않는다.
버블링은 중단을 시킬 수 있는데 event.stopPropagation() 메서드를 통해서 더 이상의 버블링을 중단 시킬 수 있다.
이때, stopPropagation은 하나의 요소에 여러 개의 이벤트 핸들러가 바인딩 된 경우에 핸들러 중 하나가 멈추더라도 나머지 핸들러는 여전히 동작한다.
요소에 할당된 다른 핸들러의 동작도 막으려면 event.stopImmediatePropagation()을 사용해야 한다.
이벤트 위임은 이벤트 핸들링 패턴 중 하나이다.
버블링과 캡처링을 활용하여 하나의 이벤트를 여러 요소들의 공통으로 사용할 수 있다면 상위 요소 하나에게만 이벤트를 적용시켜서 이벤트 핸들러를 각 요소에 바인딩 하지 않아도 된다는 장점이 있다.
이벤트 위임은 다음과 같은 알고리즘으로 동작한다.
1. 컨테이너에 하나의 핸들러를 할당한다.
2. 핸드러의 event.target 을 사용해 이벤트가 발생한 요소가 어디인지 알아낸다.
3. 원하는 요소에서 이벤트가 발생됐다고 확인되면 이벤트를 핸들링 한다.
만약 3개의 버튼이 있고, 각각의 기능을 수행할 수 있는 메서드가 주어졌을 때 한번의 이벤트 할당으로 3개의 버튼에 이벤트 위임을 할 수 있다.
<div id="menu">
<button data-action="save">저장하기</button>
<button data-action="load">불러오기</button>
<button data-action="search">검색하기</button>
</div>
<script>
class Menu {
constructor(elem) {
this._elem = elem;
elem.onclick = this.onClick.bind(this);
}
save() {alert('저장하기')}
load() {alert('불러오기')}
search() {alert('검색하기')}
onClick(event) {
let action = event.target.dataset.action;
if(action) {
this[action]();
}
}
}
</script>
바닐라 자바스크립트로 SPA를 구현하기 위해서 routing이라는 함수를 구현하고, a 태그에 data-link 속성을 바인딩해서 주소를 적어놨다.
그리고 document에 하나의 이벤트를 추가하여 모든 a 태그에 이벤트 핸들러를 등록하지 않고 a 태그에 저장된 페이지로 이동할 수 있도록 함수를 작성하였다.
document.addEventListener('click',(e) => {
// a 태그에 data-link속성을 걸어서
// 다음 라우팅 될 주소를 저장해놨다.
if(e.target.matches('[data-link]') {
e.preventDefault();
history.pushState(e.target.href,null,e.target.href);
routing(router); // vanillar javascript로 SPA 구현
}
})
팀원이 검색 창에서 검색을 할 시에 어느 곳이든 '/'를 눌르면 검색창이 포커즈가 될 수 있도록 구현을 하였는데 코멘트를 남기던 도중에도 '/'를 눌르면 검색 창으로 올라가는 이슈가 있었다. 해당 이슈를 해결하기 위해서 아래와 같은 방식으로 적용했다.
window.addEventListener('keydown', e => {
// select은 유틸 함수로
// select(selector) === document.querySelector(selector) 역할을 한다.
const slash = select(`input[data-key=${e.code}`);
if(!slash) return;
// selectAll은 select과 같은데 querySelectorAll이다.
const notActive = Array.from(selectAll('input')).every(el => el !== document.activeElement);
if(notActive) slash.focus();
...
})
벨로그 크롬 익스텐션 개발 중에 툴바에 들어가있는 템플릿 버튼을 눌르면 드롭다운 메뉴처럼 템플릿을 선택할 수 있도록 개발하였다.
그 과정에서 템플릿 버튼이거나 혹은 그 안에 모든 요소들을 선택했을 경우에는 드롭다운 메뉴가 닫히지 않고 그 외의 요소를 클릭했을 경우에는 드롭다운 메뉴가 닫힐 수 있도록 구현하엿다.
document.addEventListener('click',(e) => {
const selectors =
['.template-wrapper *',
'.template-btn *',
'.template-btn',
'.template-wrapper'
];
const matched = selectors.some(selector => e.target.matches(selector);
if(matched) {
return;
}
// 현재 드롭다운 메뉴가 열려있으면 닫는다.
const $templateContentContainer = select()('.template-content-container');
if (
$templateContentContainer &&
$templateContentContainer.classList.contains('active')
) {
$templateContentContainer.classList.remove('active');
}
})