버블링을 활용한Event 부여

동적으로 생성되는 DOM 요소에 이벤트를 부여해야 하는 경우가 있습니다.  먼저 Add Button 이라는 이름의 버튼이 하나 있고, 그 버튼을 누를때 마다 More 라는 버튼이 생성된다고 해봅니다. 그리고 More 버튼을 누를때 마다 console에 More! 라는 메세지를 띄웁니다. 먼저 HTML 문서는 다음과 같이 구성합니다.

<body>
  <button id="add-button">Add Button</button>
  <div id="button-area">
  </div>
</body>

그리고 Javascript(jQuery를 활용합니다)는 다음과 같이 작성합니다.

$('#add-button').on('click', function($event) {
  $event.preventDefault();
  var code = '&lt;button class="more"&gt;More&lt;/button&gt;';

  $('div#button-area').append( code );
  $('.more').on('click', function( $event ) { 
    $event.preventDefault();
    console.log( 'More!' ); 
  });
});

일단 겉보기에는 별다른 문제가 없이 작동합니다. 하지만 콘솔창을 띄워보면 문제가 발생한 것을 알 수 있습니다. More 버튼을 3개 생성한 후 More 버튼을 눌러보면 첫번째 버튼을 클릭했을 때 콘솔창에는 More! 메세지가 3번씩, 두 번째 버튼을 2번씩 생성됩니다.

버튼이 생성될 때마다 ‘more’ 라는 클래스를 가진 DOM 요소에 이벤트를 부여했기 때문에 먼저 생성된 more 버튼에는 버튼을 생성한 횟수만큼 이벤트가 쌓입니다. 이를 다음과 같이 수정해 보겠습니다.

$('#add-button').on('click', function($event) {
  $event.preventDefault();
  var code = '<button class="more">More</button>';

  $('div#button-area').append( code );
  $('.more').off('click').on('click', function( $event ) {  
    //.off('click') 이 추가되었습니다.
    $event.preventDefault();
    console.log( 'More!' ); 
  });
});

이제 정상적으로 작동합니다. 버튼이 생성될 때 일단 more 클래스를 가진 모든 DOM 요소의 click 이벤트를 제거한 다음 다시 click 이벤트를 부여하기 때문이죠. 하지만 뭔가 꺼림직합니다. 버튼을 누를 때마다 Javascript는 모든 more 버튼에 이벤트를 제거하고 생성하는 작업을 반복합니다. 불필요한 자원 낭비죠. 처음 한번만 이벤트를 생성할 수는 없을까요? 가능합니다.

$('div#button-area').on('click', '.more', function( $event ) {
  $event.preventDefault();
  console.log( 'More!' ); 
});

$('#add-button').on('click', function($event) {
  $event.preventDefault();
  var code = '<button class="more">More</button>';

  $('div#button-area').append( code );
});

Add button은 More 버튼을 생성하는 기능만을 수행하고 이벤트를 부여하는 코드를 밖으로 뺐습니다. 근데 이벤트가 More 버튼이 아니라 그 상위 요소인 div#button-area에 지정되어 있군요! 그리고 on() 함수의 두번째 매개 변수가 callback 함수가 아닌 ‘.more’로 변경되어 있습니다. 일단 이 코드는 정확하게 우리가 원하는데로 작동합니다.

이와 같은 현상(?)은 이벤트 버블링이라는 자바스크립트 기능때문에 발생합니다. div#button-area를 포함한 이 DOM 요소의 자식요소에서 클릭 이벤트가 발생하면 누가 이 이벤트를 발생시켰는지 확인합니다. 그리고 on() 함수의 두번째 매개변수로 지정한 ‘.more’ 가 클릭이벤트를 발생시킨 범인(?)으로 확인되면 callback 함수가 비로소 실행됩니다. 이렇게 되면 div#button-area가 존재하는 한 몇개의 More 버튼이 생성되더라도 이벤트는 항상 발생하고, 중복으로 이벤트가 발생하는 일도 없어집니다.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>