JavaScript Event Propagation

Let's Just Go·2022년 6월 23일
1

JavaScript

목록 보기
7/10

JavaScript

Event Propagation

  • Event Propagation

    • 이벤트는 전파(Propagation) 가능

    • Bubbling & Capturing

      • Capturing : 이벤트가 상위 요소에서 하위 요소로 전파
      • Bubbling : 이벤트가 하위 요소에서 상위 요소로 전파

    • event객체.stopPropagation();

      • 버블링을 막아주는 역할 즉, 하위 요소에서 상위 요소로 이벤트가 전파되는 것을 막아주는 함수
      • 자식에게 고유한 이벤트만 부여하고 싶을 때 사용
    • Code

      <!DOCTYPE html>
      <html lang="en">
      
      <head>
          <meta charset="UTF-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Document</title>
      </head>
      <style>
          #fruits {
              padding: 50px;
              border: 2px solid skyblue;
          }
      
          #fruits>li {
              background: yellowgreen;
              margin-bottom: 10px;
              font-size: 20px;
              font-weight: bold;
              text-align: center;
          }
      </style>
      
      <body>
          <!-- ul#fruits>li*3 -->
          <ul id="fruits">
              <li>Apple</li>
              <li>Banana</li>
              <li>Grape</li>
          </ul>
      
          <script>
              const $fruits = document.getElementById('fruits');
      
              function m(event) {
                  console.log('ul에 클릭 이벤트가 발생!');
                  console.log('이벤트 핸들러가 붙은 타겟 : ' + event.currentTarget);
                  console.log('실제 이벤트가 발생한 요소 : ' + event.target);
              }
      
              
              $fruits.addEventListener('click', m);
              // ul태그인 fruits에만 이벤트를 걸었는데 li태그를 클릭하면 li태그에서도 이벤트가 발생
      
              function apple(event) {
                  console.log('apple에 클릭 이벤트가 발생 ')
                  // li의 첫번째 태그에 클릭을 하게 되면 apple()이 먼저 실행되고 이후 부모에 걸린 이벤트도 실행됨
      
                  // 이벤트 전파를 중단하고 싶을 때 (버블링을 방지 )
                  event.stopPropagation();
                  // apple함수 이후 m함수가 실행되어 이벤트가 전파되는 것을 방지하기 위해 
                  // $fruits에 걸린 이벤트에 전파되지 않음
              }
              $fruits.firstElementChild.addEventListener('click', apple);
          </script>
      </body>
      
      </html>

  • Event Propagation2

    • 이벤트는 전파된다는 성질을 이용

    • 특정 요소에서만 이벤트가 발생하도록 하는 로직 구현

    • matches() 함수를 사용하여 특정 조건에서 이벤트가 실행되도록 구현

    • Code

      <!DOCTYPE html>
      <html lang="en">
      
      <head>
          <meta charset="UTF-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Document</title>
      
          <style>
              #fruits {
                  list-style: none;
                  padding: 0;
                  font-weight: bold;
                  font-size: 30px;
              }
      
              #fruits li {
                  width: 100px;
                  cursor: pointer;
              }
      
              #fruits .active {
                  color: blue;
                  text-decoration: underline;
                  text-align: center;
              }
          </style>
      </head>
      
      <body>
      
          <ul id="fruits">
              <li id="apple" class="active">APPLE</li>
              <li id="banana">BANANA</li>
              <li id="grape">GRAPE</li>
              <li id="strawberry">STRAWBERRY</li>
              <li id="tomato">TOMATO</li>
          </ul>
      
          <div>선택된 과일 : <em class='msg'>apple</em></div>
      
          <br>
      
          # 새로운 과일 추가 :
          <input type="text" class="text-box">
          <button id="add">추가</button>
      
          <script>
              const $fruits = document.getElementById('fruits');
              const $msg = document.querySelector('.msg');
              const $liList = [...$fruits.children];
      
              // 이벤트 핸들러 함수 
              function activate(event) {
      
                  // 이벤트 발생 타깃이 특정 요소인지 검증 
                  // li에만 이벤트가 발생하도록 
                  if (!event.target.matches('#fruits > li')) {
                      // matches() : 선택자를 사용하여 이벤트 발생 요소를 검증
                      // fruits안에 li가 매칭이 안된다면 이벤트가 발생하면 안되는 곳 
                      console.log('여기는 이벤트가 발생하면 안됩니당~');
                      return;
                      // 이벤트 강제 종료 
      
                  } else {
                      // console.log('여기는 이벤트가 발생해도 됨');
      
                      for (let $target of $liList) {
                          // li요소들이 하나씩 들어옴 
      
                          // toggle 메서드의 두번째 매개값으로 논리값을 전달할 수 있고 
                          // 해당 논리값이 true로 판명나면 지정한 클래스를 추가하고
                          // false로 판명나면 지정한 클래스를 삭제
                          $target.classList.toggle('active', $target === event.target);
                          // toggle은 있으면 삭제해주고 없으면 생성해줌 
                          // toggle은 조건을 걸어줄 수 있음 
      
                      }
                      $msg.textContent = event.target.textContent;
      
                      // msg태그의 text부분을 현재 이벤트가 발생한 부분의 텍스트를 가져와서 넣음 
                  }
              }
              // ul에 event를 등록 (li가 많아서 하나씩 걸어주기 귀찮음 )
              $fruits.addEventListener('click', activate);
      
              
              // 동적으로 과일 추가 기능 
              const $btn = document.getElementById('add');
              const $textBox = document.querySelector('.text-box');
      
              function cl(event) {
                  const $newLi = document.createElement('li');
                  // li요소 생성 
      
                  $newLi.textContent = $textBox.value;
                  // 새롭게 생성한 li요소에 textbox에 저장되어 있는 값을 넣어줌
      
                  $newLi.setAttribute('id', $textBox.value.toLowerCase());
                  // 새롭게 만든 li요소에 id 추가
      
                  $fruits.appendChild($newLi);
                  $textBox.value = '';
                  // 다시 입력받을 수 있도록 비워줌
      
                  $liList.push($newLi);
                  // 새롭게 추가된 li에도 이벤트를 부여하기 위해 위에 있는 $liList추가
                  // 중요 
      
              }
      
              
              // 버튼에 event 등록 
              $btn.addEventListener('click', cl);
              // li가 많기 때문에 각각 event를 걸어주는 것을 비효율적
      
          </script>
      </body>
      
      </html>

  • Propagation Stop

    • 버블링으로 인해 반복 event 실행을 막아주기 위해서는 event.stopPropagation();를 통해서 버블링 차단

    • Capturing

      • 상위요소에서 하위요소로 전파
      • addEventListener();의 매개값으로 true를 주게 되면 Capturing 실행
    • event객체.preventDefault();

      • 태그들의 고유한 기능을 막아줌
      • event를 실행시킬 때 태그에 고유한 기능이 있다면 해당 기능을 막아줄 때 사용
    • Code

      <!DOCTYPE html>
      <html lang="en">
      
      <head>
          <meta charset="UTF-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Document</title>
      </head>
      <style>
          .root {
              width: 500px;
              height: 500px;
              background: blue;
          }
      
          .parent {
              width: 50%;
              height: 50%;
              /* root의 50% */
              background: orange;
          }
      
          .child {
              width: 50%;
              height: 50%;
              /* parent의 50% */
              background: chartreuse;
          }
      </style>
      
      <body>
      
          <a href="https://www.naver.com">네이버로 이동</a>
      
          <br>
      
          <div class="root">
              <div class="parent">
                  <div class="child"></div>
              </div>
          </div>
      
          <script>
              function a(event) {
                  alert('root 클릭 확인');
              }
      
              function b(event) {
                  alert('parent 클릭 확인');
                  // event.stopPropagation();
                  // parent에서만 event가 실행될 수 있도록 함
              }
      
              function c(event) {
                  alert('child 클릭 확인');
                  // event.stopPropagation();
                  // child에서만 event가 실행될 수 있도록 함
              }
      
              document.querySelector('.root').addEventListener('click', a, true);
      
              document.querySelector('.parent').addEventListener('click', b, true);
              // addEventListener의 매개값으로 true를 주게 되면 capturing(버블링 반대) 실행 
      
              document.querySelector('.child').addEventListener('click', c);
      
              // a태그에 event 걸기 
              const $link = document.querySelector('a');
      
              function d(event) {
                  if (!confirm('정말 이동하시겠어요?')) {
      
                      // 사용자가 취소를 누르게 되면 현재 페이지에 머무르도록
                      event.preventDefault();
                      // 태그의 고유 기능을 막음 
      
                  }
              }
              $link.addEventListener('click', d);
          </script>
          <script>
      
          </script>
      </body>
      
      </html>
profile
안녕하세요! 공부한 내용을 기록하는 공간입니다.

0개의 댓글