jineecode
이벤트 위임 본문
개요: li를 하나하나 DOM을 만들고 클릭 이벤트를 걸고 한땀한땀 active를 거는 막노동을 하고 있을 때 뭔가 이상하고 비효율적임을 느낀 나는 언젠가 들어봤던 이벤트 위임을 떠올리고 적용해보기로 함.
간단히 말해, 부모를 클릭하면 자식이 수행하는 원리이다.
(이벤트 위임을 사용하면 요소마다 핸들러를 할당하지 않고, 요소의 공통 조상에 이벤트 핸들러를 단 하나만 할당해도 여러 요소를 한꺼번에 다룰 수 있습니다. 출처: ko.javascript.info/event-delegation)
HTML
<ul class="categories">
<li class="categories_btns active">
<strong class="category_btn"
>GODIVA 역사<i class="fas fa-angle-down"></i
></strong>
<p>Our Belegian Heritage</p>
</li>
<li class="categories_btns">
<strong class="category_btn"
>GODIVA 기원<i class="fas fa-angle-down"></i
></strong>
<p>The legend of Lady Godiva</p>
</li>
<li class="categories_btns">
<strong class="category_btn"
>GODIVA 초콜릿<i class="fas fa-angle-down"></i
></strong>
<p>GODIVA chocolate</p>
</li>
<li class="categories_btns">
<strong class="category_btn"
>GODIVA 쉐프<i class="fas fa-angle-down"></i
></strong>
<p>Meet Our Chefs</p>
</li>
<li class="categories_btns">
<strong class="category_btn"
>GODIVA 책임<i class="fas fa-angle-down"></i
></strong>
<p>GODIVA Care</p>
</li>
</ul>
부모태그 ul 에 click 이벤트를 걸어, 클릭한 자식 태그인 li 에 active 를 넣고 싶은 상황
첫 번째엔 active를 미리 넣어주었다.
CSS
.categories_btns {
width: 20%;
padding: 20px 30px;
background: #f8f4eb;
color: #3b1a0f;
border: 0;
outline: 0;
cursor: pointer;
}
.categories_btns.active {
color: #f8f4eb;
background: #3b1a0f;
}
active가 들어간 list 에는 컬러와 백그라운드를 반전시켜두었다.
JS
이전에 적어두었던 이벤트 게시물을 참조하여 이벤트 위임을 적용해보았다.
const categories = document.querySelector(".categories");
let currentMenu;
function clickHandler(e) {
if (currentMenu) {
currentMenu.classList.remove("active");
} e.target.classList.add("active");
currentMenu = e.target;
}
categories.addEventListener("click", clickHandler);
이 코드의 문제는 해당 li를 눌렀을 때 적용은 되지만, li 하위 요소의 태그를 눌렀을 때 li의 active가 빠지고 하위 태그에 active가 붙는다.
(이벤트 위임이 필요 없는 하위 요소가 있을 경우, 불필요한 이벤트가 발생.)
이를 해결할 수 있는 메서드가 closest() 이다.
closest(): 기준 Element 에서부터 closest() 메소드를 통해 자신부터 부모 요소 단위로 출발하여 각 요소가 지정한 선택자에 만족할 때까지 탐색한다(문서 루트까지 이동). 이 중 가장 가깝게 조건에 만족한 부모 요소가 반환되며, 조건에 만족한 요소가 없으면 null 값을 반환한다. (- 출처 developer.mozilla.org/ko/docs/Web/API/Element/closest)
function clickHandler(e) {
let target = e.target.closest('li');
if (currentMenu) {
currentMenu.classList.remove("active");
} target.classList.add("active");
currentMenu = target;
}
categories.addEventListener("click", clickHandler);
오늘도 또 하나 해결 ^^*
See the Pen abBEGmq by HyejinUm (@uhj1993) on CodePen.
올려놓고 보니 처음 active 걸어준 것이 사라지지 않는다. 😩
클릭 이벤트가 한 번 시작해야만 active class들이 사라질 수 있어서 해당 클래스를 클릭 이벤트 밖에서 한 번 컨트롤 해주어야 한다.
activate 와 inactivate 함수를 만들어 이벤트를 시작하기 전, 바깥에서 함수를 한 번 돌게 만들었다.
const categories = document.querySelector(".categories");
const cateArti = document.querySelectorAll(".cate_arti");
let currentMenu;
let currentContent;
function activate(elem){
elem.classList.add("active");
currentMenu = elem;
}
function inactivate(elem){
currentMenu.classList.remove("active");
}
function clickHandler(e) {
if (currentMenu) {
inactivate(currentMenu);
}
activate(e.target.closest('li'));
}
categories.addEventListener("click", clickHandler);
activate(document.querySelectorAll('.categories_btns')[0]);
See the Pen jOVYzEd by HyejinUm (@uhj1993) on CodePen.
'JS' 카테고리의 다른 글
스코프 & 클로저 (0) | 2021.04.26 |
---|---|
지역 선택 JS로 제어하기 (2) | 2021.02.26 |
깨알 기초 지식 모음 (0) | 2021.02.14 |
끝말잇기 만들기 (0) | 2020.12.08 |
EVENT (0) | 2020.11.26 |