target vs currentTarget

위 주제에 대해 알기 전에 필요한 몇 가지 개념도 같이 언급해 본다.

이벤트와 DOM 노드

모든 브라우저 이벤트 핸들러는 콘텍스트(context)에 등록된다. 이벤트 리스너는 해당 이벤트 리스너가 등록된 객체의 콘텍스트에서 해당 이벤트가 발생할 때만 호출된다.

<button>Click me</button>
<p>No handler here.</p>

<script>
  let button = document.querySelector("button");
  button.addEventListener("click", () => {
    console.log("Button clicked");
  });
</script>

이 예제는 버튼 노드에 핸들러를 추가한 모습이며, 버튼의 클릭을 통해 해당 핸들러가 실행되고 그 밖에 문서의 나머지 부분을 클릭하면 실행되지 않는다.

하나의 노드는 단 하나의 onclick 속성만 가질 수 있기 때문에 이러한 방식으로 노드당 하나의 핸들러만 등록할 수 있다. addEventListener 메서드는 여러 핸들러를 등록할 수 있도록 해주며, 요소에 이미 다른 핸들러가 있는 경우라도 핸들러를 안전하게 추가할 수 있다.

전파(propagation)

대부분의 이벤트 유형에서 자식 노드가 있 노드에 등록된 핸들러는 자식 노드에서 발생하는 이벤트도 수신한다. 단락 안에 있는 버튼을 클릭하면 단락의 이벤트 핸들러에서도 해당 클릭 이벤트를 확인할 수 있다. 하지만 단락과 버튼 모두 핸들러를 가지고 있다면 더 구체적인 버튼의 핸들러가 먼저 시작된다.

이것은 이벤트가 발생한 노드에서부터 해당 노드의 부모 노드와 문서의 루트까지 외부로 전파된다고 말한다. 결국 특정 노드에 등록된 모든 핸들러가 차례로 처리되고 난 후 전체 창에 등록된 핸들러에서 이벤트에 응답할 수 있다. 어느 시점에서든 이벤트 핸들러는 이벤트 객체의 stopPropagation 메서드를 호출해 이벤트 핸들러에서 이벤트를 더 이상 수신하지 못하게 할 수 있다. 예를 들어 클릭 가능한 다른 요소가 포함된 버튼이 있고 해당 버튼을 클릭해 다른 요소의 클릭 동작을 비활성화하고 싶은 경우 사용할 수 있다.

target vs currentTarget

  • 대부분의 이벤트 객체에는 객체가 시작된 노드를 참조하는 target 속성이 있다. 이 속성을 사용하면 처리하지 않아야 하는 노드에서 전파된 이벤트를 실수로 처리하는 것을 방지할 수 있다.

  • target 속성을 사용해 특정 유형의 이벤트에 대해 넓은 범위로 처리할 수도 있다.

  • 예를들어 긴 버튼 목록을 가진 노드의 경우, 버튼이 클릭됐는지 여부를 알아내기 위해 모든 버튼에 핸들러를 개별적으로 등록하는 대신에, 외부 노드에 하나의 클릭 핸들러를 등록한 다음 target 속성을 사용하는 편이 더 편리하다.

<button>A</button>
<button>B</button>
<button>C</button>

<script>
  document.body.addEventListener("click", event => {
    if(event.target.nodeName === "BUTTON") {
      console.log("clicked", event.target.textContent);
    }
  });
</script>
  • 참고로 요소를 클릭하면 'click' 이벤트가 요소의 <body> 노드까지 버블링된다.

<body> 
  <p> 
    <a href="#">일부<span>텍스트</span></a> 
  </p> 
 </body>
  • currentTarget은 이벤트 핸들러가 붙착된 것을 가리킨다. 즉, event.target은 부모로부터 이벤트가 위임되어 발생하는 자식의 위치, 내가 클릭한 자식 요소를 반환한다. 하지만 currentTarget은 이벤트가 부착된 부모의 위치를 반환한다.

  • target은 이벤트를 트리거한 요소(예: 사용자가 클릭), currentTarget은 이벤트 리스너가 연결된 요소이다.

참고) 이벤트의 기본 동작

대부분의 이벤트는 해당 이벤트와 관련된 기본 동작을 가진다. 예를 들어 링크를 클릭하면 해당 링크의 대상으로 이동한다. 아래 방향 화살표를 누르면 브라우저에서는 페이지를 아래로 스크롤한다. 마우스 오른쪽 버튼을 클릭하면 콘텍스트 메뉴가 나온다 등이 있다.

대부분의 이벤트 유형에서 자바스크립트 이벤트 핸들러는 기본 동작이 발생하기 전에 호출된다. 보통은 이런 이벤트를 미리 처리하기 때문에 기본 동작을 사용하지 않으려면 이벤트 객체에서 preventDefault 메서드를 호출한다.

이 방법은 키보드 단축키나 콘텍스트 메뉴를 구현하는데 사용할 수 있다. 그리고 사용자가 기대하는 행동을 명확히 제한하는데 사용할 수 있다. 물론 기대한 동작이 실행되지 않을 때 해당 페이지를 사용하는 사람은 불편함을 느끼게 된다. 브라우저에 따라 특정 이벤트는 전혀 개입할 수 없다. 예를 들어 크롬에서는 현재 탭을 닫는 키보드 단축키(ctrl+w, command+w)를 자바스크립트로 처리할 수 없다.

Last updated