[JavaScript] 이벤트 버블링 / 이벤트 캡처링

suyeon·2022년 6월 14일
0

Frontend

목록 보기
18/19
post-thumbnail

💫 이벤트 버블링(Event Bubbling)

  • 어떤 요소에 대한 이벤트가 발생했을 때, 해당 요소의 최상위 부모까지 이벤트가 전달되어지는 과정
  • 자식노드에서 부모노드 순으로 이벤트를 실행
  • JavaScript는 기본적으로 이벤트 버블링을 기반으로 동작한다. ★★★

🌞 BOM Event > 이벤트 버블링

  <div id="p1" class="box"> 
    <div id="p2" class="box">
      <div id="p3" class="box"></div>
    </div>
  </div>
  
  <script>
    const box1 = document.getElementById('p1');
    const box2 = document.getElementById('p2');
    const box3 = document.getElementById('p3');

    p1.onclick = function(event) {
        alert('빨강'); // 빨강
    };
        
    p2.onclick = function(event) {
        alert('노랑'); // 노랑 빨강
    };

    p3.onclick = function(event) {
        alert('파랑'); // 파랑 노랑 빨강
        
        // 이벤트 버블링을 여기서 중단해라.
        // event.cancelBubble = true;
    };

  </script>

💫 이벤트 캡처링(Event Capturing) = 이벤트 터널링(Event Tunneling)

  • 어떤 요소에 대한 이벤트가 발생했을 때 최상위 부모로부터 이벤트가 발생된 요소까지 이벤트가 전달되어지는 과정
  • 부모노드에서 자식노드 순으로 이벤트를 실행

이벤트 캡처링 방법

  • 세번째 인자
    • true : 이벤트 캡처링 할거야
    • false / 아예 쓰지 않음 : 이벤트 버블링 할거야
target.addEventListener('이벤트', 콜백 함수, {capture:ture});;

🌞 DOM Event > 이벤트 버블링 or 이벤트 캡처링(이벤트 터널링)

[예제] 이벤트 캡처링

  <div id="p1" class="box"> 
    <div id="p2" class="box">
      <div id="p3" class="box"></div>
    </div>
  </div>
  
  <script>
    const box1 = document.getElementById('p1');
    const box2 = document.getElementById('p2');
    const box3 = document.getElementById('p3');

    p1.addEventListener('click', function() {
      alert('빨강'); // 빨강
    }, true);

    p2.addEventListener('click', function() {
      alert('노랑'); // 빨강 노랑
    }, true);

    p3.addEventListener('click', function() {
      alert('파랑'); // 빨강 노랑 파랑
    }, true);
    };

  </script>

[예제] 이벤트 버블링

  <div id="p1" class="box"> 
    <div id="p2" class="box">
      <div id="p3" class="box"></div>
    </div>
  </div>
  
  <script>
    const box1 = document.getElementById('p1');
    const box2 = document.getElementById('p2');
    const box3 = document.getElementById('p3');

    p1.addEventListener('click', function() {
      alert('red');
    });

    p2.addEventListener('click', function() {
      alert('yellow');
    },false);

    p3.addEventListener('click', function() {
      alert('blue');
    });

  </script>

[예제] Hover Table 1

  <h1>테이블</h1>

  <table class="table">
    <tr>
      <td>item</td>
      <td>item</td>
      <td>item</td>
      <td>item</td>
      <td>item</td>
    </tr>
    <tr>
      <td>item</td>
      <td>item</td>
      <td>item</td>
      <td>item</td>
      <td>item</td>
    </tr>
    <tr>
      <td>item</td>
      <td>item</td>
      <td>item</td>
      <td>item</td>
      <td>item</td>
    </tr>
    <tr>
      <td>item</td>
      <td>item</td>
      <td>item</td>
      <td>item</td>
      <td>item</td>
    </tr>
    <tr>
      <td>item</td>
      <td>item</td>
      <td>item</td>
      <td>item</td>
      <td>item</td>
    </tr>
    </table>
  • <tr> -> 이벤트 매핑
  • 행 단위로 색상 바꾸기
    const table = document.getElementsByClassName('table')[0];

    const row = table.firstElementChild.children; // table.tbody.tr
   
    // var 안됨 -> i가 전역변수라서, let 됨 -> i가 지역변수
    for (let i=0; i<row.length; i++) {
     
      // 이벤트를 건 당사자 != event.target = tr
      // 이벤트가 걸린 당사자 = td
      row[i].onmouseover = function(event) {
        // row[i].bgColor = 'gold'; // 사용해도 되지만, 사용하지 않는다.

        // event.srcElement.bgColor = 'gold'; // 비표준
        // event.target.bgColor = 'gold'; // 표준

		// <행 단위로 색상 바꾸는 방법>
        // 1. target > td이니깐, td 부모에다가 이벤트를 걸면 우리가 원하는 결과를 얻을 수 있음
        event.target.parentElement.bgColor = 'gold';
        
        // 2. 이벤트를 발생시킨 태그
        event.currentTarget.bgColor = 'gold';
      };

      row[i].onmouseout  = function(event) {
        event.currentTarget.bgColor = 'transparent';
      };
    };

  • 테이블에서는 영역이 겹치기 때문에 무조건 event.srcElement는 td에 걸리게 된다.
  • 영역이 겹쳐있는 상태에서 자식이 존재하면 이벤트는 자식까지 왔다가 유턴을 한다.

[예제] Hover Table 2

  <h1>테이블</h1>

  <table class="table" id="tbl2">
    <tr>
      <td></td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td></td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td></td>
      <td></td>
      <td></td>
    </tr>
  </table>

  <script>
    const tbl2 = document.getElementById('tbl2');
    const trlist = tbl2.firstElementChild.children;

    for (let i=0; i<trlist.length; i++) {
            
        const tdlist = trlist[i].children;

        for (let j=0; j<tdlist.length; j++) {

            tdlist[j].addEventListener('mousedown', function(event) {

                if (event.buttons == 1) {
                    
                    if (event.target.nodeName == 'TD') {
                        
                        let img = document.createElement('img');
                        img.setAttribute('src', 'images/rect_icon01.png');
                        event.target.appendChild(img);

                    } else {
                        //기존 이미지 제거
                        let td = event.target.parentElement;

                        td.removeChild(event.target);

                        let img = document.createElement('img');
                        img.setAttribute('src', 'images/rect_icon01.png');
                        
                        td.appendChild(img);
                    }

                } else if (event.buttons == 2) {

                    if (event.target.nodeName == 'TD') {

                        let img = document.createElement('img');
                        img.setAttribute('src', 'images/rect_icon02.png');
                        event.target.appendChild(img);

                    } else {
                        //기존 이미지 제거
                        let td = event.target.parentElement;

                        td.removeChild(event.target);

                        let img = document.createElement('img');
                        img.setAttribute('src', 'images/rect_icon02.png');
                        
                        td.appendChild(img);
                    }

                } else if (event.buttons == 4) {

                    // 부모가 자식을 삭제
                    event.target.parentElement.removeChild(event.target);

                }
            });
        }
    }

    window.oncontextmenu = function() {
      return false;
    };

  </script>

0개의 댓글