-
자바스크립트로 리스트에 이벤트 다는 방법 ( Event delegation / 이벤트 위임 )Knowledge/javascript 2019. 8. 12. 21:51반응형
먼저 자바스크립트로 이벤트를 걸기 위해선 어떻게 해야할까?
querySelector나 getElementBy를 활용해 이벤트를 걸 대상을 찾고
addEventListener를 활용해 원하는 이벤트를 걸어주면 된다
코드로 보면 아래와 같다
12345678910111213141516171819202122232425<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>자바스크립트 이벤트</title><style>#target {width: 100px;height: 100px;background: blue;};</style></head><body><div id="target"></div><script>document.querySelector("#target").addEventListener("click",function(){alert("테스트");});</script></body></html>그렇다면 같은 클래스명을 공유하는 여러개의 엘리먼트에 한번에 이벤트를 주기 위해선 어떻게 해야 할까?
querySelectorAll을 활용해 대상을 한꺼번에 찾고 이벤트를 달 때 for문을 활용하는 것만 약간 다르지
전체적은 방법은 비슷하다. 예제 코드는 아래와 같다
12345678910111213141516171819202122232425262728293031323334<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>자바스크립트 이벤트</title><style>.target {width: 100px;height: 100px;background: blue;margin-bottom: 20px;};</style></head><body><div id="first" class="target"></div><div id="last" class="target"></div><script>var target = document.querySelectorAll(".target");var tartgetLength = target.length;for(var i=0; i < tartgetLength; i++){target[i].addEventListener("click",function(){console.log("#"+this.id+"에 이벤트 추가");});}</script></body></html>쉽다. 여기까지는 굳이 포스팅까지 할 필요가 없는 사안이다.
그러나 상상력을 발휘해서 가정을 한번 해보자.
만약 100개의 리스트가 있고 여기에 모두 이벤트 리스너가 필요하다면?
그 때도 이 방법이 효율적일까? 그렇다고 대답하는 개발자는 많지 않을 것이다.
실제로 브라우저가 기억하고 있어야 하는 이벤트 리스너 갯수가 많아져서 메모리를 많이 사용해야 하고
ajax로 엘리먼트를 추가하면 그 때마다 이벤트 리스너도 추가해줘야 하는 상황이 발생한다.
그럼 이 문제를 효율적으로 해결하려면 어떻게 해야 할까?
이벤트 위임이라는 방법이 있다.
일단 이를 이해하기 위해 자바스트립트 이벤트 특성을 아래 코드와 결과를 보자
12345678910111213141516171819202122232425262728293031323334<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>자바스크립트 이벤트</title><style>.target {width: 100px;height: 100px;background: blue;};</style></head><body><div class="one target"><div class="two target"><div class="three target"></div></div></div><script>var targets = document.querySelectorAll('.target');targets.forEach(function(target) {target.addEventListener('click', logEvent);});function logEvent(event) {console.log(event.currentTarget.className);}</script></body></html>div 세개를 겹쳐놓고 클릭시엔 현재 타켓의 클래스 명을 클릭하는 이벤트다.
그런데 클릭하면
콘솔에 세개가 찍힌다.
어떻게 된 일일까?
세개가 겹쳐져 있으니 클릭된 건 가장 위에 있는 .three target만 콘솔에 찍혀야 맞는 것 아닐까?
그러나 위 결과가 말해주듯 자바스크립트의 이벤트는 전달된다.
이처럼 하위 엘리먼트부터 상위 엘리먼트로 퍼져나가는 걸 이벤트 버블링
이렇게 상위 엘리먼트로부터 하위 엘리먼트로 퍼져나가는 걸 이벤트 캡쳐링이라 한다
12345678910var targets = document.querySelectorAll('.target');targets.forEach(function(target) {target.addEventListener('click', logEvent,{capture : true});});function logEvent(event) {console.log(event.currentTarget.className);}캡쳐링은 아래와 같이 addEventListener의 세번째 인자 위치에서 capture를 true로 설정하면 감지할 수 있다
( false가 기본값 )
사실 굳이 버블링과 캡쳐링을 구현해보지 않더라도 이런 특성은
12345678var targets = document.querySelectorAll('.target');targets.forEach(function(target) {target.addEventListener('click', logEvent);});function logEvent(event) {console.log(event);}이렇게 event만 콘솔로 찍어봐도 알 수 있다
path에 순서대로 window까지 찍혀있는 것을 보이는가?
원래 하던 이야기로 돌아가서 이벤트 위임은 이러한 javascript 특성을 살려서
상위 엘리먼트 하나에만 이벤트를 줘서 하위 엘리먼트들의 이벤트를 제어하는 방식이다
본격적으로 이벤트 위임에 대해 알아보자
- 이벤트 위임
123456789101112131415161718192021222324252627282930313233343536373839<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>자바스크립트 이벤트</title><style>ul{background: blue;}li{background: yellow;}a{background: red;text-decoration: none;color : black;}</style></head><body><ul><li><a href="#">하나</a></li><li><a href="#">둘</a></li><li><a href="#">셋</a></li><li><a href="#">넷</a></li><li><a href="#">다섯</a></li></ul><script>var ul = document.querySelector('ul');ul.addEventListener("click",function(e){console.log(e.target);});</script></body></html>사실 별 거 없다. 이렇게 ul 하위에 li > a 가 여러개 있을 경우
상위 엘리먼트인 ul 하나에만 클릭 이벤트 리스너를 달아서 제어하는 것이다.
이렇게 세팅해서 각 부분을 클릭해보면
클릭한 그 부분이 콘솔에 찍히는 걸 볼 수 있다.
그러면 이제 저 부분들을 이용해서 각자 원하는 기능을 구현하면 된다.
하나 팁을 주자면 이렇게 막 구현한 코드 말고
실제로 리스트를 구성하는 ul > li > a는 영역이 엄격히 구분되어 있지 않다.
유저는 a를 클릭하고 싶어서 a를 클릭했는데 li가 클릭되고 이런 경우가 있을 수 있다는 말.
그렇기 때문에 이벤트 위임을 이용할 때는 if 문을 활용해
e.target.tagName이 'A' 일 경우 / e.target.tagName이 'LI' 일 경우 / e.target.tagName이 'UL' 일 경우
각각 엄격히 처리해 두는 것이 훗날 정신 건강에 좋다
ps. 오류가 없도록 최선을 다했지만 배우는 입장에서 작성한 포스트입니다.
틀린 부분을 지적해주신다면 확인해보고 감사히 반영하겠습니다.
참고 :
반응형'Knowledge > javascript' 카테고리의 다른 글
javascript 객체 리터럴 패턴과 생성자 패턴, prototype (0) 2019.09.09 데이터 바인딩을 도와주는 handlebars.js 사용법 (0) 2019.08.26 setTimeout에서 this사용하는 방법! (0) 2019.08.26 CSS와 javascript는 눈보다 빠르다 슬라이드와 무한슬라이드 (6) 2019.08.13 script 태그 위치와 onload, DOMContentLoaded, ready (0) 2019.08.13