이벤트 버블링과 캡처링, 위임 (1)

9199 단어 JavaScriptEventEvent

1. 이벤트란?

이벤트(event)란 웹 브라우저가 알려주는 HTML 요소에 대한 사건의 발생을 의미합니다.

웹 페이지에 사용된 자바스크립트는 이렇게 발생한 이벤트에 반응하여 특정 동작을 수행할 수 있습니다. 따라서 클라이언트 측 자바스크립트를 비동기식 이벤트 중심(event-driven) 의 프로그래밍 모델이라고 합니다.
💁 출처

🤔 그래도 뭔지 감이 안잡힌다면 , 자주 사용되는 DOM 이벤트를 알아보자..!

  • click
  • keydown,keyup
  • submit .. 등등

이것들을 다 한번씩은 써봤을 것이다.

이벤트 핸들러

이벤트에 반응하려면 이벤트가 발생했을 때 실행되는 함수인 핸들러(handler) 를 할당해야한다.
핸들러는 사용자의 행동에 어떻게 반응할지를 자바스크립트 코드로 표현한 것이다.

function sayThanks() {
  alert('감사합니다!');
}

elem.onclick = sayThanks;

💁 여기서 주의해야할 점이 있다.

// 올바른 방법
button.onclick = sayThanks;

// 틀린 방법
button.onclick = sayThanks();

이때 함수는 sayThanks처럼 할당해야 한다. sayThanks()를 할당하면 동작하지 않는다.
나도 실수를 한적이 있다. 근데 왜 안되는지에 대해서는 생각해보지 않았다. 🥲

왜 안될까? 🤔

sayThanks() 같이 괄호를 덧붙이는 것은 함수를 호출하겠다는 것을 의미한다. 위 예시의 마지막 줄처럼 sayThanks()를 프로퍼티에 할당하면 함수 호출의 결괏(result)값이 할당되기 때문!

이벤트 객체

이벤트가 발생하면 브라우저는 이벤트 객체(event object) 라는 것을 만든다. 여기에 이벤트에 관한 상세한 정보를 넣은 다음, 핸들러에 인수 형태로 전달한다.

이벤트 객체에서 지원하는 프로퍼티 중 일부..

  • event.type
    이벤트 타입, 위 예시에선 "click".
  • event.currentTarget
    이벤트를 처리하는 요소. 화살표 함수를 사용해 핸들러를 만들거나 다른 곳에 바인딩하지 않은 경우엔 this가 가리키는 값과 같음, 화살표 함수를 사용했거나 함수를 다른 곳에 바인딩한 경우엔 event.currentTarget를 사용해 이벤트가 처리되는 요소 정보를 얻을 수 있음

2. 버블링

먼저 예시부터 살펴보자
아래 핸들러는 <div>에 할당되어 있지만,<em> 이나 <code>같은 중첩 태그를 클릭해도 동작한다.

<div onclick="alert('div에 할당한 핸들러!')">
  <em><code>EM</code>을 클릭했는데도 <code>DIV</code>에 할당한 핸들러가 동작합니다.</em>
</div>

왜 그럴까? 🤔

한 요소에 이벤트가 발생하면, 이 요소에 할당된 핸들러가 동작하고, 이어서 부모 요소의 핸들러가 동작한다. 가장 최상단의 조상 요소를 만날 때까지 이 과정이 반복되면서 요소 각각에 할당된 핸들러가 동작한다.

<style>
  body * {
    margin: 10px;
    border: 1px solid blue;
  }
</style>

<form onclick="alert('form')">FORM
  <div onclick="alert('div')">DIV
    <p onclick="alert('p')">P</p>
  </div>
</form>

가장 안쪽의 <p>를 클릭하면 어떻게 될까?

  1. <p>에 할당된 onclick 핸들러가 동작
  2. 바깥의 <div>에 할당된 핸들러가 동작
  3. 그 바깥의 <form>에 할당된 핸들러가 동작
  4. document 객체를 만날 때까지, 각 요소에 할당된 onclick 핸들러가 동작

이런 동작 방식 때문에 <p> 요소를 클릭하면 p → div → form 순서로 3개의 alert 창이 뜬다..!

event.target

부모 요소의 핸들러는 이벤트가 정확히 어디서 발생했는지 등에 대한 자세한 정보를 얻을 수 있다.
이벤트가 발생한 가장 안쪽의 요소는 타깃(target) 요소라고 불리고, event.target을 사용해 접근할 수 있다.

event.target vs this(=event.currentTarget)

  • event.target은 실제 이벤트가 시작된 ‘타깃’ 요소, 버블링이 진행되어도 변하지 않음
  • this는 ‘현재’ 요소로, 현재 실행 중인 핸들러가 할당된 요소를 참조

그러면 , 가장 안쪽 <p>를 클릭하면 event.target과 event.currentTarget가 무엇일까?
event.target은 실제 이벤트가 시작된 곳이니까 event.target.tagName은 p 이고,
event.currentTarget은 <form> 요소에 있는 핸들러가 동작했기 때문에 event.currentTarget.tagName은 form 이다.

그러면 <p> 요소를 클릭했을시에 p → div → form 순서로 3개의 alert 창이 뜨는데 p의 alert창 뜨게 하려면 어떻게 해야할까?

event.stopPropagation();을 사용하면 된다 😊

<body onclick="alert(`버블링은 여기까지 도달하지 못합니다.`)">
  <button onclick="event.stopPropagation()">클릭해 주세요.</button>
</body>

아래 예시에서 <button>을 클릭해도 body.onclick은 동작하지 않는다.!

event.stopImmediatePropagation()

🧐 한 요소의 특정 이벤트를 처리하는 핸들러가 여러개인 상황에서, 핸들러 중 하나가 버블링을 멈추더라도 나머지 핸들러는 여전히 동작한다. event.stopPropagation()은 위쪽으로 일어나는 버블링은 막아주지만, 다른 핸들러들이 동작하는 건 막지 못한다. 버블링을 멈추고, 요소에 할당된 다른 핸들러의 동작도 막으려면 event.stopImmediatePropagation()을 사용해야 한다. 이 메서드를 사용하면 요소에 할당된 특정 이벤트를 처리하는 핸들러 모두가 동작하지 않는다.

다음장에 캡처링과 위임까지..😅

reference

좋은 웹페이지 즐겨찾기