본문 바로가기
CodeIt_Sprint/JavaScript_중급

(7)JavaScript중급_3_4_이벤트 위임 문제 , 해결방법은 if조건절 + event.contains() 메소드

by 코잼민 2024. 11. 13.

#Default 상황 :

  • 아래와 같이, 기존의 ul태그 li태그 항목들이 있다.
  • 각 li 태그에 클릭을 하게 될 경우, .done 클래스의 css 스타일 add되어, 항목이 완료됐다는 이벤트 핸들러 적용

클릭하면, 투명도 적용 + 중간밑줄 적용

 

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>이벤트 위임</title>
  <style>
    .done {
      text-decoration: line-through;
      opacity: 0.5;
    }
  </style>
</head>

<body>
  <h3 id="title">오늘 할 일</h3>
  <ul id="list">
    <li class="item">자바스크립트 공부 </li>
    <li class="item">유투브 시청 </li>
    <li class="item">저녁 약속 </li>
    <li class="item">독서 </li>
    <li class="item">일기 쓰기 </li>
  </ul>

  <script>
    const list = document.querySelector('#list');


    for (let i of list.children) {
      i.addEventListener('click', function (event) {
        event.target.classList.add('done');
      });
    }

    const li = document.createElement('LI');

    li.textContent = "자살하기";

    document.querySelector('#list').append(li);

  </script>
</body>

</html>

● 문제 상황 :

- JavaScript 코드에서 li 요소 노드 - "자살하기"를 한개 더 추가하게 되면, "자살하기" li 요소노드는 해당 스타일 시트 적용이 되지 않는다.

- 이유. 코드 순서상 기존의 li 요소노드들만("자살하기" 제외) addEventListener()만 적용되어있다.

● ★해결 방법 : 요소노드.classList프로퍼티 메소드 contains('class속성값')메소드

①. 그의 상위 노드인 <ul> 노드에 addEventList()로 이벤트 핸들러 적용

=> li를 눌러도 적용되고, li가 아닌 ul을 눌러도 적용됨

②.if조건절 +  contains()메소드를 이용해, li가 있는 부분만 시트 적용되도록 한다

정답 :


    /*
    기존 addEventListener() 이벤트 핸들러 적용
    for (let i of list.children) {
      i.addEventListener('click', function (event) {
        event.target.classList.add('done');
      });
    }
    
    */

    list.addEventListener('click',function(event){
      
      if(event.target.classList.contains('item')){
        event.target.classList.add('done');
      }

    });

    const li = document.createElement('LI');

    li.classList.add('item');//item 클래스 추가 깜빡함

    li.textContent = "자살하기";

    document.querySelector('#list').append(li);

 최종적으로, 이 방법이 event 위임 과정의 정석이므로, 암기할정도로 숙지하여, 자주 사용하셈

◎ 연습문제 :

실습 설명

지용이는 지난 번에 이벤트 객체와 반복문을 활용해서 할 일을 완료하는 기능을 만들었습니다.

잠깐동안 자신이 만든 코드를 보며 흐뭇해 하긴 했지만 금세 몇 가지 문제를 발견하게 되었습니다.

자바스크립트로 새롭게 할 일을 추가하게 되면 이벤트 핸들러를 새롭게 등록해 주어야 한다는 문제를 발견했고, 이벤트 핸들러를 불필요하게 많이 등록하면 프로그램의 성능에도 부정적인 영향을 미친다는 사실도 알게 되었습니다.

이번에도 지용이는 이를 어떻게 해결할지 막막한데요.

지용이를 위해 아래 조건에 맞는 코드를 작성해 주세요.

  1. 1. 이벤트 위임을 활용할 수 있도록 이벤트 핸들러 updateToDo 함수를 완성해 주세요.
    1. updateToDo는 이벤트가 발생한 대상이 item이라는 클래스 속성 값을 가지고 있을 때 동작해야 합니다.
  2. 2. 이벤트 핸들러를 li 태그 각각에 등록하는 것이 아니라 하나의 태그에만 등록해 주세요.

코드를 잘 작성했다면, 아래 내용처럼 페이지가 동작해야 합니다.

  1. 1. 첫 번째 두 번째 할 일 뿐만아니라 자바스크립트로 추가한 네 번째 할 일을 클릭할 때도 'done'이라는 class 속성값이 toggle되면서 스타일 변해야 합니다.
  2. 2.★ 세 번째 할 일은 클릭을 해도 아무런 변화가 없어야 합니다.

디폴트 출력 장면

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>오늘 할 일</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="main">
    <h2 class="title">오늘 할 일</h2>
    <ul id="to-do-list">
      <li class="item">자바스크립트 공부하기</li>
      <li class="item">고양이 화장실 청소하기</li>
      <li class="item">고양이 장난감 쇼핑하기</li>
    </ul>
  </div>
  <script src="index.js"></script>
</body>
</html>
body {
  margin: 0;
  padding: 0;
	display: flex;
	align-items: center;
	justify-content: center;
}

.main {
	width: 350px;
	margin: 40px;
  padding: 30px 0;
  background-color: #FCFCFC;
  box-shadow: -5px -5px 20px #DFDFDF,  5px 5px 20px #BABECC;
  border-radius: 8px;
  text-align: center;
}

.title {
	margin: 15px auto;
	font-size: 30px;
	font-weight: 600;
	color: #9600FF;
}

#to-do-list {
  width: 280px;
	margin: 0 auto 15px;
	padding: 0;
	list-style: none;
}

#to-do-list li {
	display: flex;
	align-items: center;
	justify-content: center;
  width: 90%;
  height: 40px;
	margin: 8px auto 15px;
	border-bottom: 1px solid #9600FF;
	cursor: pointer;
}

.done {
  opacity: 0.5;
  text-decoration: line-through;
}

● 풀이 과정 : 

①. 클릭시, "done" class 가 추가 되도록 하는 updateToDo() 메소드 작성 (+ if 조건절 + 요소노드.classList.contains('태그내용') 적용)

②. li 태그들의 상위 요소노드에 이벤트 핸들러 적용

③. 새로운 <li> 요소노드 "가계부 정리하기" 추가하기

④. 세번째는 적용 배제 => removeEventListener();

 정답 :

const toDoList = document.querySelector('#to-do-list');

// 1. updateToDo 함수를 완성해 주세요
function updateToDo(event) {
 if(event.target.classList.contains('item'))
 {
   event.target.classList.add('done');
   
 }
}

// 2. 각 li 태그가 아니라 하나의 태그에만 이벤트 핸들러를 등록해 주세요
toDoList.addEventListener('click',updateToDo);

// 테스트 코드
const newToDo = document.createElement('li');
newToDo.textContent = '가계부 정리하기';
newToDo.classList.add('item');
toDoList.append(newToDo);

//세번째는 클릭해도 적용안되도록 배제하기 => removeEventListener()
toDoList.children[2].addEventListener('click', function(e) {e.stopPropagation()});