jineecode

이벤트 위임 본문

JS

이벤트 위임

지니코딩 2021. 2. 25. 15:05

개요: 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

 

이전에 적어두었던 이벤트 게시물을 참조하여 이벤트 위임을 적용해보았다.

jineecode.tistory.com/12

 

EVENT

1. id=main-title의 배경색을 파란색으로 바꿀 것임. event google 클릭하세요 event는 어떤 사건이며, 버튼을 클릭하면 이벤트가 발생하며 어떤 동작이 일어남. 2. 버튼을 클릭하면 바꿔야하므로 일단 js

jineecode.tistory.com

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가 붙는다.

 

(이벤트 위임이 필요 없는 하위 요소가 있을 경우, 불필요한 이벤트가 발생.)

 

 

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
Comments