[JS] 이벤트 버블링 / 캡쳐링 / 위임

AREUM·2023년 1월 24일
0

Javascript실행

목록 보기
7/7
post-thumbnail

addEventListener사용법만 알았는데, 체크리스트 만들다가 이렇게 돌고 돌아 깊게 공부하게 되었다. 똑같은 문제로 하루 종일 잡고 있으니, 지치긴했는데 해결책을 알게 되었음 된거다. ( 다독다독😭 )

관련 메소드 들도 공부하고 정리 해보았다. 그렇다면, 레 - 고 ☝🏻

이벤트 버블링

하위에서 상위 요소로 이벤트 전파방식을 이벤트버블링 이라고 한다.

특정 화면 요소에서 이벤트가 발생했을 때 해당 이벤트가 더 상위의 화면 요소들로 전달되어 가는 특성을 가지고 있다.

<body>
  <div class="green">그린
    <div class="yellow">옐로우
      <div class="tomato">토마토</div>
    </div>
  </div>
</body>
const divs = document.querySelectorAll("div");
divs.forEach(function(div) {
  div.addEventListener("click", logEvent);
});

function logEvent(event) {
  console.log(event.currentTarget.className);
}

green div, yellow div, tomato div를 각각 클릭하게 되면 콘솔에 찍히는 건 무엇일까 ?

여기서 궁금증 해결해보자.

  • 한개를 클릭했을 뿐인데 3개의 이벤트가 발생한다.
    왜 why ? : 브라우저가 이벤트를 감지하는 방식 때문이다.

  • 브라우저는 특정 화면요소에 이벤트가 발생했을 때, 그 이벤트를 최상위에 있는 화면요소까지 이벤트를 전파한다. 따라서 토마토-옐로우-그린 순서로 태그에 등록된 이벤트들이 실행된다.

  • ❗️ 주의 : 각 태그마다 이벤트가 등록되어 있기에 상위요소로 이벤트가 전달되는 것을 확인해보아야 한다.

  • 만약, 이벤트가 특정 div만 달려있으면 안된다. -> 뭔말이야 ?
    ( 이벤트 버블링, 캡쳐, 위임 이런걸 사용하지 않고, 특정 요소에게 이벤트가 정확하게 겨냥하고 있다면, 이럴 경우는 addEventListener사용보단, 그냥 onClick()을 사용하라는 말인 것 같다. )

이벤트 캡쳐링

이벤트 버블링과 반대방향으로 진행되는 이벤트 전파 방식이다.

const divs = document.querySelectorAll("div");

divs.forEach(function(div) {
  div.addEventListener("click", logEvent, {
    capture: true // default 값은 false입니다.
  });
});

function logEvent(event) {
  console.log(event.currentTarget.className);
}
  • capture : true : 이벤트 감지를 위해 이벤트 버블링과는 반대반향으로 탐색한다.

    이벤트와 비교하면 토마토를 클릭했을 때, green가 먼저 찍힌걸 볼 수 있다.

event.stopPropagation();

: 복잡한 이벤트 전달방식을 알고 싶지 않고, 그냥 원하는 화면 요소의 이벤트만 신경쓰고 싶을 때 사용된다.

function logEvent(event) {
  event.stopPropagation();	// 이 api는 이벤트가 전달되는 것을 막는다.
}

따라서 버블링은 해당 이벤트만 발생한다. ( 상위요소 전파를 방해 )

사용법

divs.forEach(function(div) {
  div.addEventListener("click", logEvent, {
    capture: true // default 값은 false입니다.
  });

  // 생략 가능
  div.addEventListener("click", logEvent, true);
});

function logEvent(event) {
  event.stopPropagation();
  console.log(event.currentTarget.className); // one
}

번외 : 또 다른방법의 버블링, 캡쳐링, 위임을 꾸역꾸역 막기 위한 방법

조건문을 이용해 주는것.

const green = document.querySelector('.green');
  green.addEventListener('click',function(e){
    const { target, currentTarget } = e;
  
    if ( target !== currentTarget ) return
    
    console.log("currentTarget : ", currentTarget.className);
    console.log("Target : ", target.className);
  })

if문의 설명은
👉🏻 클릭한 대상의 targetcurrentTarget이 동일하지 않다면, 클릭한 대상이 자기 자신일 때만 동작하도록 한다.

🌟이벤트 위임 - event Delegation

하위 요소에 각각 이벤트를 붙이지 않고 상위요소에서 하위요소의 이벤트들을 제어하는 방식

<h1>체크 리스트</h1>
<ul class="itemList">
	<li>
		<input type="checkbox" id="list1">
		<label for="list1">이벤트 리스트 1</label>
	</li>
	<li>
		<input type="checkbox" id="list2">
		<label for="list2">이벤트 리스트 2</label>
	</li>
	<li>
		<input type="checkbox" id="list3">
		<label for="list3">이벤트 리스트 3</label>
	</li>
</ul>
/*
var inputs = document.querySelectorAll('input');
inputs.forEach(function(input) {
	input.addEventListener('click', function(event) {
		alert('clicked');
	});
});
*/

// 상위 ul tag에 이벤트 부여 , 이벤트 버블링 효과에 따라 아래 li에 요소가 추가되도 이벤트 실행 가능
var itemList = document.querySelector(".itemList");
itemList.addEventListener("click", function(event) {
  // target을 이용해 클릭할 때마다, text에 style의 효과를 주었다.
  event.target.style.textDecoration = !event.target.style.textDecoration ? 'line-through' : '';
});

// 새 리스트 아이템을 추가하는 코드
var itemList = document.querySelector(".itemList");

var li = document.createElement("li");
var input = document.createElement("input");
var label = document.createElement("label");
var labelText = document.createTextNode("이벤트 위임 학습");

input.setAttribute("type", "checkbox");
input.setAttribute("id", "list4");
label.setAttribute("for", "list4");
label.appendChild(labelText);
li.appendChild(input);
li.appendChild(label);
itemList.appendChild(li);

  1. 이벤트 리스트 태그가 1, 2, 3 이렇게 3개가 있다.
  2. 새 리스트를 추가 해준다.
  3. 그리고 setAtttribute를 이용해 id type for를 지정해준다.
  4. 그러면 화면을 보았을 때, list4가 생겼다.

이 부분을 체크리스트에서 input에 입력칸을 만들어서 사용하면 될 것같다.
addEventListener 클릭이벤트에서는 체크리스트를 제일 크게 감싸고 있는 ul태그에 addEventListener를 이용해 클릭을 했을 때, 처리되는 화면의 기능을 넣어주었다.


각 요소마다 addEventListener를 걸어 주는 방법을 사용하거나, (
주석처리 부분은 이벤트 위임을 이용하지 않은 전의 작업처리이다. ) 각 리스트인 input을 모두 찾아 forEach()로 돌려주고 이벤트를 걸어주게 되면, 코드가 굉장히 지저분 하고 비효율적일 것이다.


많은 걸 알았다.
빨리 진도 나가야되겠다.
나도 얼른 잘 만든 코드를 만들고 싶다. 발전하자!

그럼 이만 - 🙌🏻

유용해서 자주 이용하는 블로그다.😀😀😀😀😀👍🏼👍🏼👍🏼
참고한 사이트

profile
어깨빵으로 부딪혀보는 개발끄적이는 양씨 인간

0개의 댓글