본문 바로가기
프로그래밍/jQuery

on(), 이벤트 바인딩 하기

by zoo10 2012. 2. 24.

on

원문 링크 http://api.jquery.com/on/

.on( events [, selector] [, data] , handler(eventObject) )Returns : jQuery

개요 : 선택된 요소에 하나 이상의 이벤트들을 붙여줍니다.

  • .on( events [, selector] [, data], handler(eventObject) )
  • events 공백으로 구분된 하나 이상의 이벤트 타입과 옵션인 네임스페이스. "click", "keydown.myPlugin", ".myPlugin" 등이 있음.
  • selector 이벤트가 발생할 요소들의 자식들을 찾을 선택자 문자열. 만일 선택자가 null 이거나 생략됬다면, 이벤트는 선택된 요소에 도달할때만 실행됩니다.
  • data 이벤트가 발생할 때 핸들러에 전달할 데이터.
  • handler(eventObject) 이벤트가 발생되면 실행될 기능. false를 반환하는 함수라면 간단하게 false 를 직접 인자로 하면 된다.
  • .on( events-map [, selector] [, data] )
  • events-map 공백으로 구분된 하나 이상의 이벤트 타입과 선택적인 네임스페이스로 구성된 키(keys)들과 값(values)들의 문자열.
  • selector 이벤트가 발생할 요소들의 자식들을 찾을 선택자 문자열. 만일 선택자가 null 이거나 생략됬다면, 이벤트는 선택된 요소에 도달할때만 실행됩니다.
  • data 이벤트가 발생할 때 핸들러에 전달할 데이터.

.on() 함수는 jQuery 객체 안의 현재 선택된 요소 집합과 이벤트 핸들러를 묶어 줍니다. jQuery 1.7 에 와서, .on() 함수는 이벤트 핸들러 바인딩에 필요한 모든 기능을 제공합니다. 이전 버젼의 jQuery 이벤트 함수에 대한 도움말을 원하시면, .bind(), .delegate(),.live() 함수에 대한 내용들을 참고하십시요. .on() 으로 바인딩한 이벤트를 해제하는 방법에 대해서는, .off() 함수를 참고하십시요. 한번만 실행되는 이벤트를 부착하고 그 자체를 제거하려면.one() 함수를 참고하십시요.

이벤트 명과 네임스페이스 ( Event names and namespaces )

어떤 이벤트 명도 events 인자로 사용할 수 있습니다. 브라우져의 일반적인 click과 같은 사용자 동작 이벤트를 생성하면 jQuery는 handler는 함수를 호출하여 브라우져의 표준 Javascript 이벤트 타입을 사용합니다. 덧붙여, .trigger() 함수는 표준 브라우져 이벤트와 사용자 정의 이벤트 모두를 바인딩된 handler들을 통하여 발생시킬 수 있습니다.

와우 무슨 이런 형이상학적인 말이 있죠. ㅎㅎ;; 이해하자면 jquery로 이벤트를 바인딩하면 결국 브라우져의 기본 이벤트를 사용하게 되는 것과 마찬가지다 정도이지 않을까요.

이벤트 명을 event namespaces 로 사용하면 간단하게 이벤트를 제거하거나 발생시킬 수 있습니다. 예를 들어, "click.myPlugin.simple" 는 특정 click 이벤트에 myPlugin 과 simple 이라는 네임스페이스를 정의한 것입니다. click 이벤트 핸들러는 .off("click.myPlugin").off("click.simple") 구문을 사용하여 요소의 다른 이벤트 핸들러에 영향을 주지않고 제거될 수 있습니다. 네임스페이스는 단 하나의 이름만 일치해야하는 부분에서 CSS 클래스와 유사합니다. 밑줄(underline)로 시작하는 네임스페이스는 jQuery가 예약하여 사용하고 있습니다.

헉, 점입가경~~. 점점 미궁속으로~. 요것도 풀면 네임스페이스를 사용하면 접근성이 좋아지고 다른 부분에 영향을 주지 않고 사용할 수 있다는 얘기입니다.

.on() 함수의 두번째 사용법에서 events-map 인자는 JavaScript Object 거나 "map" 입니다. 키(keys)는 공백으로 구분된 이벤트 타입과 네임스페이스로 이루어진 events 문자열 입니다. 각 키(key)의 값(value)은 함수의 마지막 인자 대신에 핸들러로 사용되는 기능(function) 또는 false 값입니다. 다른 관점에서는, 두가지 형태는 아래쪽에 설명한 부분같이 액션이 동일합니다.

이 부분은 events-map에 대한 얘기인데요. 직역만 해서는 무슨 얘기를 하고 싶은건지 파악이 되질 않네요. 추후에 이해가 되면 부연설명을 따로 달겠습니다.

Direct and delegated events

대부분의 브라우져 이벤트의 버블(bubble) 또는 전파(propagate)는 문서의 요소(이벤트의 타겟이 되는)에서 body 와 document 요소까지 발생하게 됩니다. Internet Explorer 8 이하의 브라우져들은, changesubmit 같은 몇몇 이벤트들에 대해 기본적으로 버블(이벤트 전파, bubble)를 지원하지 않지만 jQuery 는 크로스 브라우져를 위해 지원하고 있습니다.

만일 selector 가 생략되거나 null 이면, 이벤트 핸들러는 direct 또는 directly-bound(직접 바인딩)으로 처리합니다. 핸들러는 선택된 요소에 이벤트가 발생할 때마다 호출이 되고, 요소의 상위나 하위 요소들에 전파가 됩니다.

selector 를 인자로 넘기면, 이벤트 핸들러는 delegated 처럼 작동합니다. 이 핸들러는 바인딩된 요소의 상위 요소들에서 이벤트가 발생했을 때 호출이 되지않고 하위 요소들에만 영향을 주게 됩니다. jQuery 버블(bubbles, 전파)은 이벤트 대상에서 핸들러가 연결된 요소까지(즉, 바깥쪽에서 안쪽까지) 그리고, 선택자와 일치하는 요소 모두에 발생하게 됩니다.

이벤트 핸들러는 현재 선택된 요소들에만 바인딩됩니다. 그 요소들은 페이지에 반드시 존재해야 .on() 함수로 호출할 수 있습니다. 요소가 존재하고 선택할 수 있다면, 페이지의 HTML 마크업의 요소를 문서가 준비되면 이벤트와 바인딩 할 수 있게 됩니다. 만약 새로운 HTML 태그가 삽입되게 되면, 그 요소를 선택하고 새로운 HTML 요소 아래쪽에 이벤트 핸들러를 바인딩 합니다. 또는, delegated events 를 사용하여 이벤트 핸들러를 바인딩할 수도 있습니다.

음, 당연한 얘기를 하고 있습니다. 새로운 요소를 삽입하고 그 요소에 이벤트를 바인딩 하고 싶으면 그 요소 아래쪽에 바인딩하는 스크립트를 작성하라는 얘기인 것 같습니다.

위임된 이벤트(Delegated events)는 나중에 추가된 요소들의 "하위요소"에도 이벤트를 바인딩할 수 있는 이점을 가집니다. 델리게이티드 이벤트(delegated event, 위임된 이벤트)가 바인딩 되는 순간, 존재하는 요소들을 모두 찾아낼수 있어서 우리는 매번 이벤트 핸들러를 붙였다 떼였다 하는 번거로움을 피할 수 있습니다. 덧붙여 아직 만들어지지 않은 하위 요소들에 이벤트를 적용시킬 수도 있습니다. 위임된 이벤트(delegated events)의 또 다른 이점으로는 부하(overhead)를 아주 낮출 수 있다는 것입니다. 테이블의 tbody 가 1,000개의 row를 가지고 있다면, 아래 예제는 1,000개의 tr 요소에 이벤트를 바인딩하는 스크립트 입니다.

$("#dataTable tbody tr").on("click", function(event){
	alert($(this).text());
});

위임된 이벤트(delegated-events) 개념으로 이벤트 핸들러를 tbody 하나의 요소에 바인딩 하면 이벤트가 발생한 한 수준 위로 버블링을 실행해 줍니다. 즉, 클릭된 tr 에서 tbody 수준으로 이벤트를 올려준다는 뜻입니다.

$("#dataTable tbody").on("click", "tr", function(event){
	alert($(this).text());
});

음 위의 두 예제를 테스트 해봤는데 같은 결과가 나타났습니다. 즉, 이벤트를 1,000줄에 거는것은 낭비라는 것이죠. 아래 예제처럼 tbody에 이벤트를 바인딩해도 같은 결과를 나타낼 수 있다는 뜻입니다. 역시 코딩은 직접 짜보고 테스트하는게 제맛~

이벤트 핸들러와 환경 ( The event handler and its environment )

handler 인자는 function이며 (또는 false 값 자체) events-map 인자가 없다면 반드시 필요합니다. 위의 예처럼 어떤 핸들러 함수라도 .on() 함수 호출 시 사용하거나 아래 예제처럼 함수를 정의하고 그것을 사용할 수도 있습니다.

function notify() { alert("clicked"); }
$("button").on("click", notify);

브라우져에서 이벤트가 발생하거나 jQuery의 .trigger()를 이용하여 Javascript를 호출할 때, jQuery 는 event object에 핸들러를 통과시킵니다. 이것은 이벤트의 상태가 변화하는 것을 분석할 수 있습니다. 이 객체는 브라우져에 제공된 데이터의 정규화의 한 부분(normalized subset) 입니다. 브라우저의 수정되지 않은 네이티브 이벤트 객체인 event.originalEvent 을 통해서 사용할 수 있습니다. 예를 들어, event.type은 "resize" 같은 이벤트 명을 포함하고 event.target은 이벤트가 발생된 깊은 안쪽 요소를 의미합니다.

와우~ 점점 하기 싫어집니다. ㅎㅎ 무슨 얘기인지~~

기본적으로 대부분의 이벤트들은 원래 이벤트 타겟에서 document 요소로 버블을 하게 됩니다. 버블링에 영향을 받는 각 요소들은 jQuery에 의해 이벤트 핸들러가 모두 호출됩니다. 핸들러는 event.stopPropagation() 함수를 사용하여 이벤트를 막을 수 있습니다. 하지만 요소에 연결된 다른 핸들러는 실행이 됩니다. 이것마저 막고 싶다면, event.stopImmediatePropagation() 함수를 사용하시면 됩니다. (이벤트 핸들러는 요소에 바인딩 된 순서대로 실행됩니다.)

비슷하게, event.preventDefault() 함수를 사용해서 이벤트의 실행을 취소시킬 수 있습니다. 예를 들어, click 이벤트의 기본적인 액션인 링크기능을 취소할 수 있습니다. 모든 브라우저 이벤트의 기본 액션들을 취소할 수 있습니다. 자세한 사항은 W3C Events Specification 을 참고하십시요.

위는 이벤트를 취소하는 방법에 대한 내용이네요.

event.stopPropagation()event.preventDefault() 함수를 호출하면 자동적으로 이벤트 핸들러는 false 를 반환합니다. false 값은 function(){ return false; } 과 같은 코드 대신에 간단하게 사용할 수 있습니다. 즉, $("a.disabled").on("click", false); 와 같이 "disabled" 클래스를 가진 모든 a 링크들의 클릭 이벤트를 취소시키고 이벤트 버블링도 방지시킵니다.

jQuery가 핸들러를 호출하면 this 키워드는 이벤트가 전달된 요소를 가르킵니다. 직접 바인딩 된 이벤트에서 "this"는 이벤트가 연결된 요소이고 selector에 의해 선택된 요소입니다. (Note 만약 이벤트가 하위 요소에서 부터 버블링 되었다면 thisevent.target 과 일치하지는 않습니다.) 요소에서 jQuery 객체를 만들었다면 $(this) 형태로 jQuery 함수에서 사용할 수 있습니다.

핸들러에 데이터 전달 ( Passing data to the handler )

만약 If a data 인자가 argument is provided to .on() 함수에 전달되고 and is not null 또는 undefined 이 아니라면, 이벤트가 발생할 때마다 event.data 속성을 통해 핸들러에 데이터가 전달됩니다. data 인자는 어떤 타입이라도 사용할 수 있지만 만일 문자열을 사용했다면 데이터 선택 실수를 방지하기 위해 selector 반드시 제공하거나 명시적으로 null 을 전달해야 합니다. 가장 좋은 선택은 다수의 value들을 전달할 수 있는 object (map) 을 사용하는 것입니다.

jQuery 1.4 에서는, 같은 event handler 는 요소에 여러번 바인딩할 수 있었습니다. 이것은event.data 기능을 사용할 때 특히 유용합니다. 예를 보면:

function greet(event) { alert("Hello "+event.data.name); }
$("button").on("click", { name: "Karl" }, greet);
$("button").on("click", { name: "Addy" }, greet);

위 코드는 버튼을 클릭하면 두번의 다른 알림창을 보여주게 됩니다.

이벤트 성능 ( Event performance )

대부분의 경우,click 과 같은 이벤트는 드물게 발생하기 때문에 성능을 크게 개의치 않아도 됩니다. 하지만, mousemove 또는 scroll 과 같은 빈도 높은 이벤트는 1초에 수십번씩 발생하고 이벤트를 잘 사용하는 것이 중요해 집니다. 성능은 핸들러 안에서 작업을 축소하고 재계산 보다 정보를 캐싱하며, setTimeout에 의해 페이지를 동적으로 구현하는 수를 제한하는 것으로 좋아질 수 있습니다.

문서 구조의 상위에 이벤트 핸들러 바인딩을 많이 하면 성능이 떨어집니다. 이벤트가 발생할 때마다, jQuery는 이벤트 타겟에서 문서 상위가지의 모든 요소들을 이벤트가 연결된 모든 선택자와 비교하게 됩니다. 가장 좋은 성능을 내려면, 이벤트 바인딩을 타겟 요소 근처에서 해야 합니다. 큰 문서에 이벤트 바인딩을 document 또는 document.body 에 하는 것은 피해야 합니다.

jQuery는 tag#id.class의 형태로 바인딩할 요소를 매우 간단하고 빠르게 선택할 수 있습니다. 그래서, "#myForm", "a.external", "button" 들은 잘 사용된 예제입니다. 더 복잡한 선택자로 바인딩된 이벤트 - 특히 계층적인 것들 - 들은 좀 느려질 수 있습니다. 계층적인 선택자는 종종 문서의 적절한 위치에서 핸들러 바인딩을 하여 쉽게 피할 수 있습니다. 예를 들어, $("body").on("click", "#commentForm .addNew", addComment) 대신에 $("#commentForm").on("click", ".addNew", addComment)으로 사용할 수 있는 것입니다.

추가 사항 ( Additional notes )

.click() 같은 함수는 이벤트 핸들러를 바인딩하거나 발생시킬 수 있습니다. 이런 함수들을 더 알고 싶으시면 events category 메뉴를 참고하십시요.

"mouseenter mouseleave" 식으로 표현해야 하는 함수를 줄여서 "hover"를 사용할 수 있습니다. 이것은 두개의 이벤트를 싱글 이벤트 핸들러 형태로 바인딩하게 됩니다. 이 핸들러를 테스트 하시려면 이벤트에 mouseentermouseleave 가 발생했을 때 event.type 을 보면 알 수 있습니다. 여기서 주의할 점은 "hover"는 .hover() 함수가 아니라는 점입니다.

jQuery의 이벤트 시스템은 요소의 속성을 통해 데이타를 묶어 이벤트를 추적하고 전달할 수 있는 DOM 요소를 요구합니다. object, embed, applet 요소들은 데이터를 바인딩하지 못하기 때문에 jQuery 이벤트는 그 요소들에 바인딩을 하지 않습니다.

예 제
p 태그를 클릭하면 알림창이 나타납니다.

$("p").on("click", function(){
alert( $(this).text() );
});

 

예 제
이벤트 핸들러에 데이터를 전달하고, foo 값을 알림창으로 보여줍니다.

function myHandler(event) {
alert(event.data.foo);
}
$("p").on("click", {foo: "bar"}, myHandler)

 

예 제
폼의 submit를 막고 false를 인자로 하여 이벤트가 버블링되는 것을 차단합니다.

$("form").on("submit", false)

 

예 제
.preventDefault() 함수로 기본적인 액션을 취소시킵니다.

$("form").on("submit", function(event) {
  event.preventDefault();
});

 

예 제
.stopPropagation()를 사용하여 폼 submit을 방해하지 않고 버블링에 의한 submit을 방지합니다..

$("form").on("submit", function(event) {
  event.stopPropagation();
});

 

예 제  
사용자 이벤트를 바인딩하고 발생시킵니다.

<!DOCTYPE html>
<html>
<head>
  <style>
p { color:red; }
span { color:blue; }
</style>
  <script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
  <p>Has an attached custom event.</p>
<button>Trigger custom event</button>
<span style="display:none;"></span>
<script>

$("p").on("myCustomEvent", function(e, myName, myValue){
  $(this).text(myName + ", hi there!");
  $("span").stop().css("opacity", 1)
    .text("myName = " + myName)
    .fadeIn(30).fadeOut(1000);
});
$("button").click(function () {
  $("p").trigger("myCustomEvent", [ "John" ]);
});

</script>

</body>
</html>

미리보기

버튼을 클릭해 보세요.

 

예 제  
map을 이용하여 동시에 여러 이벤트를 바인딩합니다.

<!DOCTYPE html>
<html>
<head>
  <style>
.test { color: #000; padding: .5em; border: 1px solid #444; }
.active { color: #900;}
.inside { background-color: aqua; }
</style>
  <script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
  <div class="test">test div</div>
<script>$("div.test").on({
  click: function(){
    $(this).toggleClass("active");
  },
  mouseenter: function(){
    $(this).addClass("inside");
  },
  mouseleave: function(){
    $(this).removeClass("inside");
  }
});</script>

</body>
</html>

미리보기

한번에 여러 이벤트를 바인딩했습니다. 쉽게 보면 이벤트들을 콤마로 쭈욱 연결하면 되네요.

 

예 제  
클릭하면 그 이후에 다른 p 요소를 추가합니다. Note .on() 새로 생긴 요소에 클릭이벤트를 버블링으로 추가해줍니다.

<!DOCTYPE html>
<html>
<head>
  <style>
  p { background:yellow; font-weight:bold; cursor:pointer;
      padding:5px; }
  p.over { background: #ccc; }
  span { color:red; }
  </style>
  <script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
  <p>Click me!</p>

  <span></span>
<script>
    var count = 0;
    $("body").on("click", "p", function(){
      $(this).after("<p>Another paragraph! "+(++count)+"</p>");
    });
</script>

</body>
</html>

미리보기

새로 생긴 요소들에도 클릭이벤트가 발생하는 것을 확인해 보세요.

 

예 제
클릭하면 각각의 p 태그의 텍스트를 보여줍니다.

$("body").on("click", "p", function(){
  alert( $(this).text() );
});

 

예 제
preventDefault 함수를 사용하여 링크의 기본 액션을 취소합니다..

$("body").on("click", "a", function(event){
  event.preventDefault();
});

 

우왁~ 대박 깁니다. 이 내용은 지속적으로 수정을 좀 해야 겠습니다. 제가 좀 써보고 군데군데 주석을 달아 보겠습니다. on 함수에 대한 글을 쓰다가 지쳐서 너무 오래걸려 버렸네요. 잘 사용하세요. jQuery에서 적극적으로 밀어주는 함수입니다.

그럼 즐프하세요.

※ 본 예제는 http://www.jquery.com 에 있는 내용임을 밝힙니다.