본문 바로가기

Language/JavaScript

<자바스크립트 기초> 13. 이벤트 (2)

 * 이벤트 위임

 - 우리는 지난 장에서 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