* 이벤트 위임
- 우리는 지난 장에서 for문을 통해 각각의 리스트에 리스너를 달아주고 클릭시 함수가 실행되도록 하는 이벤트를 만들었다. 그러나 이는 양이 많아지면 많아질수록 리스트가 많아진다. DOM 스크립트가 많아질수록 웹이 무거워지므로 우리는 리스너를 줄일 수 있는 방법을 알아보자.
- 이벤트 위임이란 리스너를 부모태그에게만 줌으로써 리스너의 사용을 최소화 하는 것이다.
var currentMenu;
var menu = document.querySelector('.menu');
function clickHandler(e) {
if (currentMenu) {
currentMenu.classList.remove('menu-active')
}
e.target.classList.add('menu-active');
currentMenu = e.target;
}
menu.addEventListener('click', clickHandler);
- 지난 장에서 본 것과 같이 currentMenu변수는 현재 클릭된 리스트를 저장시켜주는 변수이다.
- 지난 장과 달리 우리는 menu라는 변수에 리스트들의 부모를 넣어주었다.
- addEventListenr 메소드를 지난번과 동일하게 주었다. 이 때 함수에 마찬가지로 this를 활용하면 어떻게 될까. 예상했다시피 this는 리스너에서 반응하여 menu, 즉 부모태그로 인식된다.
- 이 때 사용해야 하는 것이 .target 속성이다. 핸들러는 첫번째 매개변수에 자동으로 이벤트 객체가 들어오므로 e라는 매개변수를 사용하고. e.target을 사용하면 실제로 누른 정확한 타겟이 지정된다. 즉 우리가 클릭한 리스트가 정확하게 받아진다. (참고로 this 는 .currentTarget 과 동일하다)
* 위임의 장점
- 위와 같이 부모태그에만 리스너를 사용하고 .target속성을 이용하면 리스너를 최소화 시킬 수 있다는 장점이 있다.
- 우리가 잘아는 인스타그램이나 페이스북 같이 스크롤을 내릴 때마다 계속 비슷한 구조와 이벤트를 불러올 경우 전체 컨테이너에만 넣어주면 새로 불러온 내용마다 따로 이벤트를 만들 필요가 없다.
* 이벤트 개선
- 이벤트를 작성할 때 최대한 간결하게 작성하는 것이 좋다. 그렇게 해야 재사용성이 높아지고 코드의 보수가 수월해진다.
- 이러한 간결성을 위해 함수를 따로따로 나누는 것도 좋은 방법이다.
var currentMenu;
var menu = document.querySelector('.menu');
function activate(elem) {
elem.classList.add('menu-active');
currentMenu = elem;
}
function inactivate(elem) {
elem.classList.remove('menu-active');
}
function clickHandler(e) {
if (currentMenu) {
inactivate(currentMenu);
}
activate(e.target);
}
menu.addEventListener('click', clickHandler);
activate(document.querySelectorAll('.menu-link')[2]) ;
- 이는 위에서 했던 동작과 동일한 동작을 보여주지만 코드의 길이는 더 길어졌다. 살펴보자면 활성화와 비활성화를 나누었으며, 핸들러함수에는 이 두 개의 함수를 넣어주었다.
- 이렇게 하면 코드의 길이는 길어졌지만 훨씬 간결하고 직관적이며, 따로 호출도 가능해지는 등 더 효율적이라고 볼 수 있다.
* 문제점 해결
- 우리는 지금까지 target을 통해 정밀한 타겟을 지정하여 이벤트를 주었는데 이 또한 문제가 발생한다.
- 예를 들어 버튼을 클릭했을 때 어떤 이벤트를 실행한다고 하자. 그 버튼안에는 이미지가 있을 수 있고 텍스트가 있을 것이다. 이 때 만약 버튼클릭을 위해 텍스트를 클릭하면 target은 버튼이아니라 텍스트를 지정할 것이고, 그럼 이벤트가 제대로 동작하지 않는다.
- 위를 해결하기위해 두가지 방법을 알아보자.
① CSS로 해결 : 이 방법은 매우 간단하다. 우리는 버튼에만 포인터를 인식시키고 싶은 것이므로 그 자식인 텍스트나 이미지에 pointer-events : none; 을 입력하면 된다.
이는 포인터 이벤트를 못받도록 지정하는 것이다.
하지만 이것도 단점이 존재한다. 좀 더 복잡한 코드에서 이 자식에게 이벤트를 주고싶을 수 있다. 그러나 포인터이벤트 none을 주게되면 모든 하위 객체들에게 영향을 미친다.
② JS로 해결 : 조금 복잡하지만 CSS로 해결하는 것보다 좀 더 세밀하다.
구조는 어떤 것을 클릭해서 target을 받고 이것이 우리가 원하는 것이 아니라면 부모로 거슬러올라가고 이것도 아니면 또 거슬러 올라감을 반복한다. 그래서 원하는 클래스를 찾았을 때 함수를 시행한다.
function clickHandler(e) {
let elem = e.target;
while(!elem.classList.contains('clickmenu'){
elem = elem.parentNode;
if (elem.nodeName = "BODY") {
elem = null;
return;
}
}
console.log(elem);
}
- 위의 코드를 실행하면 콘솔로그에 우리가 원하는 타겟이 정상적으로 출력될 것이다.
- 이를 자세히 살펴보면 임의로 elem이라는 변수에 e.target을 넣었다.
- while 구문으로 elem의 클래스에 우리가 원하는 클래스가 없으면 elem.parentNode 로써 부모로 거슬러 올라가고, 이것이 만약 body 태그라면 (elem.nodName이 BODY라면) return으로 함수를 종료시켰다.
- 정상적으로 원하는 클래스를 while문을 통해 발견했다면 elem에는 그 객체가 담기게 된다.
참고
이 글은 1분코딩의 자바스크립트 기본 강의와 인터랙티브 웹 개발 강의를 수강하고 개인적으로 정리하며 작성한 글입니다.
1분코딩 (유튜브)
1분코딩
제주 동쪽 바닷가 마을에 살며 주로 웹 분야의 디자인이나 개발을 하고 있어요. studiomeal@kakao.com
www.youtube.com
인프런
인터랙티브 웹 개발 제대로 시작하기 - 인프런
크리에이티브 넘치는 인터랙티브 웹페이지를 개발할 수 있는 기본기를 다질 수 있는 수업입니다. 초급 웹 개발 UX/UI Front-End HTML/CSS JavaScript 웹 퍼블리싱 웹 개발 인터랙티브 웹 온라인 강의 인터
www.inflearn.com
'Language > JavaScript' 카테고리의 다른 글
<자바스크립트 기초> 15. 애니메이션 다루기 (0) | 2020.12.22 |
---|---|
<자바스크립트 기초> 14. 스크롤 이벤트 (1) (0) | 2020.12.17 |
<자바스크립트 기초> 12. 이벤트 (1) (2) | 2020.12.10 |
<자바스크립트 기초> 11. DOM 스크립트 (2) (0) | 2020.12.08 |
<자바스크립트 기초> 10. DOM 스크립트 (1) (0) | 2020.12.03 |