728x90

자바스크립트 이벤트 델리게이션 패턴

자바스크립트

이벤트 델리게이션 패턴은 자바스크립트의 대표적인 디자인 패턴 중 하나입니다.

최근 HTML, CSS를 조작하는 웹에서 사용자의 '클릭', '호버' 등과 같은 동적인 이벤트를 관리하기 위해서 DOM에 이벤트를 작성하는 '이벤트 리스너(Event Listener)'가 있습니다. 이벤트 델리게이션 패턴은 이 이벤트 리스너를 보다 더 효율적으로 관리하기 위한 디자인 패턴입니다.

자바스크립트 이벤트 리스너

먼저, 자바스크립트의 이벤트 리스너에 대해 알아보겠습니다.

이벤트 리스너의 말 그대로 이벤트가 발생하기까지 대기하고 있습니다. 여기에서 이벤트란, 사용자가 브라우저에 하는 행동을 의미합니다.
이벤트 리스너가 엘리먼트에 추가되어 있다면 엘리먼트가 클릭되거나 마우스가 호버되고 더블클릭 등이 일어났을 때 해당 이벤트에 연결되어 있는 이벤트 리스너가 실행시킬 것입니다.

사용자가 버튼을 눌렀을 때 알림을 띄우는 리스너의 경우 다음과 같이 작성해야 할 것입니다.

  1. 버튼에 '클릭 이벤트'에 대한 이벤트 리스너를 작성합니다. 이렇게 하면 사용자가 버튼을 클릭할 때까지 이벤트 리스너가 대기하고 있습니다.
  2. 사용자가 버튼을 '클릭'했을 경우, 클릭 이벤트에 등록된 '이벤트 리스너'가 실행됩니다.

자바스크립트는 이와 같은 방법을 이용해 비동기적인 사용자의 액션을 처리할 수 있습니다. 이러한 패턴을 옵저버 패턴(관찰자 패턴)이라 합니다.

자바스크립트 이벤트 프로세스와 이벤트 전파를 중단하는 방법에 대해서는 아래 링크를 참고해주세요.

자바스크립트 이벤트 델리게이션 패턴

이제, 이 포스트의 주제인 이벤트 델리게이션 패턴에 대해서 알아보겠습니다. 이벤트 델리게이션은 이벤트 전파 과정과 이벤트 버블링, 이벤트 캡쳐링의 개념을 알고 있다면 어렵지 않게 이해할 수 있습니다. 우선, 다음 예제를 살펴보겠습니다.

<body>
    <button id="btn1">Btn1</button>
    <button id="btn2">Btn2</button>
    <button id="btn3">Btn3</button>
</body>

body 안에 3개의 button이 존재하는 경우, 각각의 버튼에 서로 다른 기능을 수행하도록 이벤트 리스너를 설정하고 싶다면 다음과 같이 이벤트 리스너를 작성하면 됩니다.

document.querySelector("#btn1").addEventListener("click", function() {
  console.log("click btn1");
});

document.querySelector("#btn2").addEventListener("click", function() {
  console.log("click btn2");
});

document.querySelector("#btn3").addEventListener("click", function() {
  console.log("click btn3");
});

하지만, button의 개수가 많아지고 심지어 DOM Element가 동적으로 변화하고 있는 상황이라면 이벤트 리스너를 하나하나 등록하는 것은 브라우저의 메모리를 많이 사용하게 될 것이고 곧 퍼포먼스 저하로 이어지게 될 것입니다.

이를 해결할 때 주로 사용되는 패턴이 이벤트 델리게이션 패턴입니다. 이벤트 델리게이션 패턴은 상위 엘리먼트에 이벤트를 준 뒤, 분기하는 것인데 버튼에 일일이 이벤트 리스너를 등록하지 않고 버튼을 감싸고 있는 body에 이벤트 이스너를 등록해서 이벤트의 target 값을 이용해 버튼의 클릭 이벤트를 지정하는 것입니다.

이벤트 발생시에 전달되는 이벤트 객체에는 Target이 명시되어 있어서 부모 노드로부터 캡쳐링을 통해 이벤트를 전달받더라도 이벤트가 어떤 엘리먼트에서 발생했는지, 어떨게 이벤트를 처리해야 하는지 알 수 있습니다.

이를 이용해 위에서 3개의 이벤트 리스너를 등록했던 코드를 다음과 같이 수정할 수 있습니다.

document.querySelector('body').addEventListener('click', function(event) {
  var target = event.target || event.srcElement;

  switch (target.id) {
    case "btn1":
      console.log("click btn1");
      break;
    case "btn2":
      console.log("click btn2");
      break;
    case "btn3":
      console.log("click btn3");
      break;
    default:
      break;
  }

  event.stopPropagation();
}, true);

위와 같이 부모 엘리먼트에 하위 엘리먼트의 리스너를 작성하는 방식을 "이벤트 델리게이션 패턴"이라 하며, 이는 자바스크립트에서 퍼포먼스를 높이는 것에 있어서 중요한 역할을 차지하고 있습니다.

여러 프레임워크에서의 이벤트 위임

Backbone.js, Ember.js, React.js와 같은 경우, 내부적으로 이벤트 위임을 하기 때문에 자체적으로 제공하는 이벤트 등록 방식을 사용하면 됩니다.

Angular.js의 경우, 자체적으로 지원하지는 않지만 angular-event-delegate 모듈을 사용해 위임을 할 수 있습니다.

728x90
728x90