상세 컨텐츠

본문 제목

jQuery.on()

프로그래밍/스크립트

by 라제폰 2015. 8. 25. 17:26

본문

원문 : http://noritersand.tistory.com/218


참고문서

http://api.jquery.com/on/

http://www.jquerykorea.pe.kr/bbs/board.php?bo_table=jquery_api&wr_id=161&sfl=wr_subject&stx=on%28%29&sop=and


.on()


하나 혹은 그 이상의 요소(노드)에 이벤트 핸들러를 부착(?)한다. 

Attach an event handler function for one or more events to the selected elements


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)들의 문자열.


on()은 1.7에서 bind(), delegate(), live()를 대체하는 메서드로 이벤트 핸들러 바인딩에 필요한 기존 메서드의 모든 기능을 제공한다.

jQuery는 1.7.x 이후의 버전에서 위 세 메서드 대신 on()으로 사용할 것을 권장하고 있다.


$(선택자).on(이벤트타입 [, 자식선택자] [, 데이터], 핸들러())


on()은 jQuery 객체를 리턴하는데, 만약 메서드의 전달인자로 추가적인 선택자를 명시하면 최초 요소의 자식 요소에서 재탐색하여 리턴한다.


1
2
3
4
5
6
7
8
9
10
11
12
$("#btn_close").on("click"function() {
    self.close();
});
 
$("#btn").bind("click"function() {});
$("#btn").on("click"function() {});
 
$("body").delegate("#btn""click"function() {});
$("body").on("click""#btn"function() {});
 
$("#btn").live("click"function() {});
$("#btn").on("click"function() {});
cs


delegate를 제외하곤(selector와 eventType의 위치가 뒤바뀜) 기존방식의 형식과 큰 차이는 없다.


주의해야 할 것은 on을 사용한다고 해서 무조건 동적처리1가 가능한것은 아니라는 점이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
    jQuery(document).ready(function() {
        $("#demo6 li").on("click"function() {
            alert($(this).text());
        });
        
        $("#demo6 button").on("click"function() {
            $("#demo6 ul").append("<li>added</li>");
        });
    });
</script>
</head>
<body>
    <div id="demo6">
        <button>ADD</button>
        <ul>
            <li>test1</li>
            <li>test2</li>
            <li>test3</li>
        </ul>
    </div>
</body>
cs

  • test1
  • test2
  • test3
  • added
  • added
  • added
  • added
  • added


문서로딩 이 후 추가되는 요소는 클릭 이벤트가 발생해도 아무런 반응이 없다. (이벤트 핸들러가 자동으로 할당 되지 않는다.) 이는 jquery의 bind()를 사용할 때 발생하는 문제와 완벽하게 일치한다. 즉 이 형식은 on()메서드가 처리하는 방식이 bind()의 그것과 똑같다는 것을 알 수 있다. 


그렇다면 노드의 동적 생성, 그리고 이 객체에 이벤트 할당은 어떻게 하는가? 방법은 on()을 좀 더 적절하게 사용하던지 아니면 delegate()를 사용하는 방법이 있다.2 이 두 방법 중 .on()의 경우는 다음 코드를 참고하자:

1
2
3
4
5
6
7
8
9
10
11
<script type="text/javascript">
    jQuery(document).ready(function() {
        $("#demo7").on("click""li"function() {
            alert($(this).text());
        });
        
        $("#demo7 button").on("click"function() {
            $("#demo7 ul").append("<li>added</li>");
        });
    });
</script>
cs

  • test1
  • test2
  • test3
  • added
  • added
  • added
  • added


이쯤에서 동적처리를 기준으로 on()의 구문을 대충 정리하자면 다음의 둘로 나뉜다.

$(선택자).on(이벤트타입 [, 추가선택자] [, 데이터], 핸들러());


1. 파라미터에 추가선택자가 없다 → bind, 동적처리 불가능

2. 파라미터에 추가선택자가 있다 → delegate, 동적처리 가능


■ events-map


on() 메서드의 파라미터인 events-map은 공백으로 구분되는 문자열, 혹은 JSON, map이 올 수 있다. 여기서 map은 생략한다.


1-1. bind 형식 - 공백으로 구분된 문자열

우선 '공백으로 구분되는 문자열'이란 다음과 같다 :

"eventType1 eventType2 eventType3..."


실제로 사용해보자:

1
2
3
4
5
6
7
8
9
10
11
12
13
<script type="text/javascript">
    jQuery(document).ready(function() {
        $("#demo8 button").on("click mouseout"function() {
            alert("이벤트 발생!");
        });        
    });
</script>
</head>
<body>
    <div id="demo8">
        <button>뚜룹뚜빠라빠라</button>
    </div>
</body>
cs


1-2. bind 형식 - JSON

반면, JSON의 경우에는 각기 다른 핸들러를 전달할 수 있다:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script type="text/javascript">
    jQuery(document).ready(function() {
        $("#demo9 button").on({
            click: function() {
                $("#demo9 #result").html("<span style='color: red;'>click event</span>")
            },
            mouseover: function() {
                $("#demo9 #result").html("<span style='color: blue;'>mouseover event</span>")
            }
        });
    });
</script>
</head>
<body>
    <div id="demo9">
        <button>뚜룹뚜빠라빠라</button>
        <div id="result"></div>
    </div>
</body>
cs


단, bind 식이라서 동적처리는 불가능하다.


2-1. delegate 형식 - 공백으로 구분된 문자열

동적처리가 가능한 delegate 형식은 다음처럼 작성한다:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<script type="text/javascript">
    jQuery(document).ready(function() {
        var cnt = 0;
 
        $("#demo10").on("click mouseover""div"function() {
            $("#demo10 #cnt").text(cnt);
            cnt++;
        });
        
        $("#demo10 button").on("click"function() {
            $("#demo10").append("<div>추가된 놈</div>");
        });
    });
</script>
</head>
<body>
    <div id="demo10">
        <button>ssup!</button> <span id="cnt"></span>
        <div>원래 있던 놈</div>
    </div>
</body>
cs

 1
원래 있던 놈
추가된 놈
추가된 놈
추가된 놈


2-2. delegate 형식 - JSON

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script type="text/javascript">
    jQuery(document).ready(function() {
        $("#demo11").on({
            click: function() {
                $("#demo11 #result").html("<span style='color: red;'>click event</span>")
            },
            mouseover: function() {
                $("#demo11 #result").html("<span style='color: blue;'>mouseover event</span>")
            }
        }, "div");
        
        $("#demo11 button").on("click"function() {
            $("#demo11").append("<div>추가된 놈</div>");
        });
    });
</script>
</head>
<body>
    <div id="demo11">
        <button>ssup!</button> <span id="result"></span>
        <div>원래 있던 놈</div>
    </div>
</body>
cs

 mouseover event
원래 있던 놈

 

■ event namespaces


네임스페이스를 활용하면 하나의 이벤트에 여러 작동을 지정하고 이를 컨트롤 해야 할 때 접근성을 쉽게 할 수 있다. 예를 들어 button태그의 click 이벤트 발생 시 한번에 네 개의 함수가 작동하도록 만든다고 하자. 이를 네임스페이스로 바인딩했다면 차후 동적처리로 특정함수를 제거해야 한다고 할 때 해당 네임스페이스를 이벤트타입으로 지정하여 삭제할 수 있다.

 

다음은 하나의 클릭 이벤트에 다수의 핸들러를 네임스페이스를 이용해 바인딩하고 그 중 일부만 삭제하는 예시다:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<script type="text/javascript">
    jQuery(document).ready(function() {
        $("#demo12 #do").on("click.first"function() {
            alert("first action");
        });
        
        $("#demo12 #do").on({
            "click.second"function() {
                alert("second action");
            },
            "click.third"function() {
                alert("third action");
            }
        });
    });
    
    function fn_del() {
        $("#demo12 button").off("click.second");
    }
</script>
</head>
<body>
    <div id="demo12">
        <button id="do">ssup!</button>
        <button onclick="fn_del()">second action 삭제</button>
    </div>
</body>
cs

 


위에서 "click.first"는 click 이벤트의 first 네임스페이스를 의미하는데 여기서 네임스페이스는 1depth 이상일 수 있다. 

이 말은 가령 "click.action.event.first"라는 네임스페이스도 가능하다는 뜻이다.


■ data


on() 메서드의 인자로 null 이나 undefined 가 아닌 data가 지정되면 이 값은 event.data 속성을 통해 핸들러에 전달된다. data 인자는 어떤 타입이라도 사용할 수 있지만 만일 문자열을 사용했다면 데이터 선택 실수를 방지하기 위해 selector를 반드시 제공하거나 명시적으로 null을 지정해야 한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script type="text/javascript">
    jQuery(document).ready(function() {
        function foo(event) {
            alert(event.data.txt1 + event.data.txt2);
        }
        
        $("#demo12 #do").on("click", {txt1: "hello", txt2: " world!"}, foo);
    });
</script>
</head>
<body>
    <div id="demo12">
        <button id="do">ssup!</button>
    </div>
</body>
cs


※ 아래는 기존 메서드의 간략 정리


.bind()


.bind( eventType [, eventData] , handler( eventObject ) )


bind()는 기본적으로 jQuery객체에 이벤트 리스너를 등록하고 해당 이벤트가 발생할 시 처리될 콜백함수를 핸들러로 전달한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
    jQuery(document).ready(function() {
        $("#demo1 li").bind("click"function() {
            alert($(this).text());
        });
    });
</script>
</head>
<body>
    <div id="demo1">
        <ul>
            <li>test1</li>
            <li>test2</li>
            <li>test3</li>
        </ul>
    </div>
</body>
</html>
cs

  • test1
  • test2
  • test3


이처럼 bind()는 이벤트 핸들링의 기본이라고 할 수 있다. JQuery는 매우 빈번하게 일어나는 이벤트들은 bind()를 거치지 않고 사용할 수 있도록 구현해놨는데 jQuery.click(), jQuery.hover() 등이 그것이다.


그런데 문제는 bind() 메서드가 동적으로 생성된 노드에 접근할수없다하기 번거롭다는 점이다.


다음 예시를 보면:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script type="text/javascript">
    jQuery(document).ready(function() {
        $("#demo2 button").bind("click"function() {
            $("#demo2 ul").append("<li>added</li>");
        });
        
        $("#demo2 li").bind("click"function() {
            alert($(this).text());
        });
    });
</script>
</head>
<body>
    <div id="demo2">
        <button>add</button>
        <ul>
            <li>test1</li>
            <li>test2</li>
            <li>test3</li>
        </ul>
    </div>
</body>
cs

  • test1
  • test2
  • test3


add 버튼 클릭 시 동적으로 생성된 노드의 li 요소는 클릭해도 아무런 반응을 보이지 않는다.

이는 bind() 메서드에 전달되는 jQuery객체가 document.ready 시점으로 한정되기 때문이다.


만약 문서로딩 이 후 추가되는 노드에 이벤트를 등록하고자 한다면 다음처럼 소스를 고쳐야 할 것이다:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script type="text/javascript">
    jQuery(document).ready(function() {
        $("#demo3 button").bind("click"function() {
            $("#demo3 li").unbind("click");
            $("#demo3 ul").append("<li>added</li>").find($("li")).click(function() {
                alert($(this).text());    
            });
        });
        
        $("#demo3 li").bind("click"function() {
            alert($(this).text());
        });
    });
</script>
cs

  • test1
  • test2
  • test3


이 외에는 자바스크립트의 버블링을 이용하는 방법이 있다.


※ 버블링이란?

계층적 구조의 포함되어 있는 특정 엘리먼트에 이벤트가 발생할 경우, 연쇄적인 반응이 일어나는데 이를 이벤트 전파라고 한다. 이벤트 대상 엘리먼트를 시작으로 최하위 엘리먼트까지 이벤트가 전파가 되는 것을 캡쳐링(Capturing)이라고 하고, 반대로 최상위 엘리먼트에서 대상 엘리먼트까지 이벤트가 전파되는 것을 버블링(Bubbling)이라 한다.

http://youngman.kr/?p=749

1
2
3
4
5
6
7
8
9
10
11
12
13
<script type="text/javascript">
    jQuery(document).ready(function() {
        $("#demo3 button").bind("click"function() {
            $("#demo3 ul").append("<li>added</li>");
        });
 
        $("#demo3").bind("click"function(e) {
            if (e.target.tagName == "LI") {
                alert($(e.target).text());
            }
        })
    });
</script>
cs


.delegate()


.delegate( selector, eventType, handler )

  • eventType: 공백으로 구분된 하나 이상의 JavaScript 이벤트를 포함하는 문자열, "click", "keydown" 또는 사용자 정의 함수명


다음은 delegate()를 사용해 동적으로 생성된 노드를 핸들링하는 코드다: 

1
2
3
4
5
6
7
8
9
10
11
12
13
<script type="text/javascript">
    jQuery(document).ready(function() {
        $("#demo4 button").bind("click"function() {
            $("#demo4 ul").append("<li>added</li>");
        });
 
        $("#demo4").delegate("li""click"function() {
            alert($(this).text());        
        });
        //jQuery.delegate()에서 jQuery객체는 파라미터:selector의 부모 요소를 선택한다.
        //따라서 $(document) 혹은 $("body"), $("html"), $("ul")등을 사용할 수 있다. 
    });
</script>
cs

  • test1
  • test2
  • test3


.live()


.live( events, handler )    

Returns Object


이번에는 live()의 사용 예다:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="http://code.jquery.com/jquery-1.6.4.js"></script>
<script type="text/javascript">
    jQuery(document).ready(function() {
        $("#demo5 button").bind("click"function() {
            $("#demo5 ul").append("<li>added</li>");
        });
 
        $("#demo5 li").live("click"function() {
            alert($(this).text());
        });
    });
</script>
</head>
<body>
    <div id="demo5">
        <button>ADD</button>
        <ul>
            <li>test1</li>
            <li>test2</li>
            <li>test3</li>
        </ul>
    </div>
</body>
</html>
cs

<데모는 생략>


live() 메서드는 1.7 이후 사용이 완전히 금지3되었기 때문에 부득이하게 1.6.4 라이브러리를 이용하여 작성했다.

보다시피 파라미터에 차이가 있을 뿐 구문은 bind(), delegate()와 크게 차이 나지 않는다.





  1. 여기서 동적처리란 문서로딩 이 후 스크립트에 의해 노드가 새로 생성될 때 해당 노드에 핸들러가 자동으로 할당되는 것을 의미한다.[본문으로]
  2. live()란 놈이 있었지만 폐기되었다. [본문으로]
  3. 실제로 1.7.x 이상의 라이브러리에서는 없는 메서드라며 오류가 난다. [본문으로]


관련글 더보기