32
How jQuery event works { Based on jQuery 2.x } 2015.12.01 Jae Sung Park [Image source] https://www.flickr.com/photos/gsfc/5600413555/

How jQuery event works

Embed Size (px)

Citation preview

Page 1: How jQuery event works

How jQueryevent works

Based on jQuery 2.x

2015.12.01

Jae Sung Park

[Image source] https://www.flickr.com/photos/gsfc/5600413555/

Page 2: How jQuery event works

jQuery event basicnamespace 사용

동일 핸들러에 여러 개의 이벤트 바인딩

$(elem).on("click.yournamespace", function(e) ... );

$(elem).on("click focus keydown", function(e) ... );

https://learn.jquery.com/events/event-basics/

Page 3: How jQuery event works

.trigger("event")

elem.trigger("click")은 실제 이벤트를 발생시키는 것이 아니라, 해당 요소에바인딩된 이벤트 핸들러만을 실행즉, 요소가 <a>라면 href를 탐색하지 않음

'this' on event handler

이벤트 핸들러 내에서의 this는 raw element를 가리킨다.jQuery로 래핑하고자 한다면 $(this)와 같이 처리필요

$("#some").on("click", function(e) this; // <== jQuery로 래핑되지 않은 <div id="some"> $(this); // <== jQuery로 래핑);

Page 4: How jQuery event works

File structureevent.js

jQuery Event API: public 이벤트 메서드

jQuery.event: helper functions & properties

jQuery.Event: 이벤트 객체jQuery.Event 객체는 를 기반으로 한다.

jQuery.fn.extend( on: function(), one: function(), off: function(), trigger: function(), triggerHandler: function() );

jQuery.event = ... ;

DOM3 이벤트

jQuery.Event = function( src, props ) ... jQuery.Event.prototype = ... ;

Page 5: How jQuery event works

Alias이벤트명 메서드를 통해 편리하게 사용할 수 있는 메서드 alias 처리

/event/alias.js

아래의 이벤트들은 jQuery.fn[event_name] 로 확장되며, 파라미터 없이 호출되는 경우 jQuery.trigger(), 그 반대는 jQuery.on()를 호출한다.

/event/ajax.js: Ajax 이벤트

blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu hover bind unbind delegate undelegate

ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend

Page 6: How jQuery event works

Event object이벤트가 바인딩된 요소에 대한 이벤트 객체를 내부 데이터 객체에 캐싱(* 내부 private 변수인 dataPriv, jQuery.data() 에서 사용하는 캐시 데이터는 dataUser)

Data 추가시 마다 Data.uid++ 증가핸들러 추가시 마다 handler.guid = jQuery.guid++ 증가

// dataPriv에 저장된 캐시를 얻어올 수 있다. jQuery._data(element);

// dataPrive에 저장된 캐시를 제거할 수 있다. // 그러나 이벤트 바인딩은 남아있고, 처리하는 핸들러에 대한 내용만 삭제된다. jQuery._removeData(element);

// Unique for each copy of jQuery on the page // expando? A property added to an object at run­time jQuery.expando = "jQuery" + ( version + Math.random() ).replace( /\D/g

// Data 객체가 생성될 때마다 unique한 key 값을 설정해 사용 function Data() ... this.expando = jQuery.expando + Data.uid++;

Page 7: How jQuery event works

Event object structure// key: element[ dataPriv.expando ] = Data.uid++dataPriv.cache[ key ] = events: focus: [ data: Variant, // 사용자가 이벤트에 전달하고자 하는 데이터 guid: 1, // handler unique key (jQuery.guid++) handler: USER_BIND_FUNCTION, // 사용자가 정의한 핸들러 namespace: String, needsContext: Boolean, origType: "click", selector: String, type: "click" , guid: 2, ... ], keydown: [ guid: 3, ... , guid: 4,

Page 8: How jQuery event works

Some points handling event동일한 이벤트를 여러번 바인딩하더라도, 실제로는 제일 처음의 이벤트만 DOM에 실질적으로 바인딩하고, 이후 바인딩되는 이벤트들은 내부 이벤트 객체 배열에 추가이벤트가 발생하면, 이벤트 객체 캐시의 handler 속성에 저장된 함수가 수행되며 이때 native event 객체를 jQuery.Event로 래핑해 파라미터로 전달jQuery.event.global을 통해 .on()으로 바인딩된 이벤트 종류를 확인 가능

이벤트명이 실제 존재하지 않는 이벤트라고 해도 addEventListener()를 통해 등록

// 페이지내에서 click과 keydown 이벤트가 바인딩 되었다면jQuery.event.global; // click: true, keydown: true

Page 9: How jQuery event works

jQuery EventExtensions

https://learn.jquery.com/events/event-extensions/

Page 10: How jQuery event works

jQuery.event.props이벤트 핸들러에 전달되는 이벤트 객체에 추가되는 속성 목록

(* .trigger()를 통해 발생되는 경우는 제외)

jQuery.event.props = ( "altKey bubbles cancelable ctrlKey currentTarget detail eventPhase " "metaKey relatedTarget shiftKey target timeStamp view which" ).split(" ");

// 모든 event 객체에 some을 추가하고자 한다면, 단순히 배열에 추가jQuery.event.props.push("some");

elem.on("event", function(event) // 핸들러로 전달되는 event 객체에 some 속성을 사용. 실제 구현은 event hook을 통해 처리 event.some;);

Page 11: How jQuery event works

jQuery event hook특정 이벤트에 대한 속성을 확장(제어)할 수 있다.

Hook은 이벤트가 발생해 처리되는 시점에 수행된다.// extend or normalize the event objectjQuery.event.fixHooks["이벤트명"] = // 브라우저 이벤트 객체에서 jQuery 이벤트 객체로 복사되어야 하는 속성명 props: [],

// 이벤트 객체를 생성한 후 실행되는 함수로, 이벤트 객체에 전달되는 속성을 핸들링할 수 있다. filter: function(event, originalEvent) ;

// ex. drop 이벤트에 dataTransfer 속성을 추가하고자 하는 경우jQuery.event.fixHooks.drop = props: [ "dataTransfer" ], filter: function(event, originalEvent) ... ;

Page 12: How jQuery event works

key & mouse hooksjQuery는 기본적으로 키보드와 마우스 이벤트에 대한 hook이 설정되어 있다.

jQuery.event.keyHooks다음의 속성 값을 키보드 이벤트 객체에 추가char charCode key keyCode

jQuery.event.mouseHooks다음의 속성 값을 마우스 이벤트 객체에 추가button buttons clientX clientY offsetX offsetY pageX pageY screenXscreenY toElement

Page 13: How jQuery event works

jQuery.event.simulate이벤트를 시뮬레이션 하기위한 메서드로,

A 이벤트가 B 이벤트와 같이 동작하도록 해야할때 사용될 수 있다.(ex. focus 이벤트를 focusin 이벤트로 동작)

jQuery.event.simulate: function( type, elem, event, bubble ) var e = jQuery.extend(new jQuery.Event(), event, type: type, isSimulated: true, // simulate 여부 값 속성 추가 originalEvent: // native 이벤트는 빈 객체로 설정 );

// 버블링 여부에 따라 .trigger() 또는 .dispatch()를 호출 if ( bubble ) jQuery.event.trigger( e, null, elem ); else jQuery.event.dispatch.call( elem, e ); ...

Page 14: How jQuery event works

Special event hooks이벤트의 동작을 특정 시점에 제어하기 위해 사용되며,제어할 이벤트에 대해 속성과 함수를 설정해 사용한다.

(* load, focus, blur, click, beforeunload 에 대한 special hook은 기본 정의되어 있다.)

jQuery.event.special["EVENT_NAME"] = // trigger()로 실행되었을 때 버블링 여부. (default false) noBubble : Boolean,

// 해당 이벤트가 지정된 이벤트(일반적으로 DOM 이벤트) 와 같이 처리되도록 한다. // "click"이라고 지정한 경우, 해당 이벤트는 click 이벤트와 같이 처리 bindType: String, delegateType: String,

// 이벤트가 바인딩될 때 실행 // 요소에 이벤트를 native(addEventListener) 바인딩 되게 하려면 return false; 필수 setup: function( data: Object, namespaces, eventHandle: function ) ... ,

// 이벤트가 제거(동일 이벤트가 여러개 등록된 경우, 마지막 이벤트)될 때 실행 // 이벤트가 제거되게 하려면 return false; 필수. teardown: function() ... ,

// 이벤트를 바인딩할 때마다 실행 // .on()을 통해 등록될 때 마다 실행됨 add: function( handleObj ) ... ,

// 이벤트를 제거할 때마다 실행

http://benalman.com/news/2010/03/jquery-special-events/

Page 15: How jQuery event works

How jQuery event flows

Page 16: How jQuery event works

Event flows

Page 17: How jQuery event works

이벤트 바인딩 시 flow$(elem).on("event", handler);

1) jQuery.event.add() 호출

2) jQuery.event.add() 실행2-1) Get cached data :

2-2) 해당 요소에서 처리할 공통 이벤트 핸들러 설정 (최초 바인딩 시에만)

return this.each( function() jQuery.event.add( this, types, fn, data, selector ); );

dataPriv.get( elem );

elemData.handle = function(e) jQuery.event.dispatch.apply() ;

Page 18: How jQuery event works

2-3) 이벤트 객체 구성

2-4) 최초 바인딩 시에만 실행되는 task:- special["event"].setup() hook 실행- 요소에 이벤트를 native bind

// 이벤트에 대한 정보 객체를 생성 후, 이벤트 객체의 "이벤트명" 키 값의 배열에 추가 // handleObj is passed to all event handlers handleObj = jQuery.extend( type: type, origType: origType, data: data, handler: handler, guid: handler.guid, // jQuery.guid++ 증가해 handler에 유니크 값 부여 selector: selector, needsContext: selector && jQuery.expr.match.needsContext.test( selector ), namespace: namespaces.join(".") , handleObjIn );

if ( elem.addEventListener ) elem.addEventListener( type, eventHandle, false );

Page 19: How jQuery event works

2-5) special["event"].add() hook 실행2-6) 핸들러 배열에 추가(handlers는 요소에 대한 내부 캐시 데이터 dataPriv를 가리킴)

2-7) 어떤 이벤트가 사용되었는지 확인을 위해 이벤트 종류를 저장

handlers.push( handleObj );

// Keep track of which events have ever been used, for event optimizationjQuery.event.global[ type ] = true;

Page 20: How jQuery event works

Flow diagram: .on()

Page 21: How jQuery event works

이벤트 발생 시 flowUser clicks an element

1) jQuery.event.dispatch() 실행모든 jQuery 이벤트 바인딩 핸들러로는 jQuery 정의 함수가 설정된다.

2) jQuery.event.dispatch() 구성2-1) jQuery.event.fix( event )이벤트에 따른 hook 처리 및 native 이벤트를 jQuery로 래핑

eventHandle = elemData.handle = function( e ) // Discard the second event of a jQuery.event.trigger() and // when an event is called after a page has unloaded return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? jQuery.event.dispatch.apply( elem, arguments ) : undefined; ;

event = new jQuery.Event( originalEvent );

Page 22: How jQuery event works

2-2) 내부 캐시 dataPriv.get( this, "events" ) 에서 저장된 핸들러를 가져온다.2-3) Special hookjQuery.event.special["event"].preDispatch(event) 실행2-4) 요소에 바인딩된 모든 동일 이벤트를 큐에 넣는다.

2-5) handlerQueue 만큼 반복하면서 핸들러를 실행해당 이벤트에 등록된 jQuery.special["event"].handle 이 존재하면, 원래 등록된 핸들러 대신 special["event"].handle 함수를 실행2-6) Special hookjQuery.event.special["event"].postDispatch(event) 실행2-7) return event.result; 반환result는 special["event"].handle 또는 바인딩한 이벤트 핸들러의 반환값

handlerQueue = jQuery.event.handlers.call( this, event, handlers );

Page 23: How jQuery event works

Flow diagram: on user 'click'

Page 24: How jQuery event works

이벤트 trigger 시 flowelem.trigger("event");

.trigger()와 .triggerHandler()는단순히 jQuery.event.trigger()를 호출해주는 역할만 수행

1) jQuery.event.trigger() 구성1-1) 새로운 이벤트 객체 생성

1-2) special["event"].trigger 실행 return 값이 false면 원래의 핸들러를 실행하지 않는다.

new jQuery.Event( type, typeof event === "object" && event );

Page 25: How jQuery event works

1-3) 이벤트 전파 경로를 작성

1-4) 등록된 이벤트 핸들러 실행1차적으로 jQuery 이벤트 핸들러 실행하고, 2차적으로 인라인 이벤트("onEvent")가 존재하는 경우, 해당 이벤트 핸들러도 실행1-5) .trigger()로 실행되었을 때만, 바운더리 내의 모든 버블링 후, 마지막에special["event"]._default() 존재하면 실행

for ( ; cur; cur = cur.parentNode ) eventPath.push( cur ); tmp = cur;

Page 26: How jQuery event works

Triggering eventjQuery에서 제공되는 트리거 함수는 .on()을 통해 추가된 이벤트 핸들러를실행하는 것으로 native 이벤트를 발생시키는 용도로 사용할 수는 없다.

native 이벤트를 발생시키고자 한다면 을 사용할 수 있다.(* use document.createEventObject for < IE9 / document.createEvent for others)

jquery.simulate

.trigger() vs .triggerHandler()triggerHandler()는 첫 번째 요소에 대해서만 핸들러를 실행체이닝 되지 않음. 핸들러의 반환값을 반환기본동작을 사용할 수 없음 (form submit 과 같은)버블링되지 않으며, 첫 번째 요소에 등록된 핸들러만 실행

https://learn.jquery.com/events/triggering-event-handlers/

Page 27: How jQuery event works

Flow diagram: .trigger()

Page 28: How jQuery event works

이벤트 제거 시 flowelem.off("event");

1) jQuery.event.remove( this, types, fn, selector ) 실행

1-1) 이벤트 분리(여러개 인 경우를 대비) 후, 반복문 실행사용자가 전달하는 파라미터가 elem.off("click mousedownkeydown");와 같은 경우[LOOP 1]1-2) 이벤트 파라미터가 전달되지 않은 경우, 모든 이벤트를 제거

if ( !type ) for ( type in events ) // recursive 하게 jQuery.event.remove()를 각각 호출 jQuery.event.remove( elem, type + types[ t ], handler, selector, true );

Page 29: How jQuery event works

1-3) 단일 이벤트에 등록된 핸들러에 대해 반복문 실행 (여러개 또는 단일)[LOOP 2]1-4) handlers.splice( j, 1 ); 핸들러 배열에서 값을 제거하는 형태로 큐에서 제거1-5) special["event"].remove()가 존재하면 실행[ End LOOP 2 & 1 ]

1-6) special["event"].teardown() 실행1-7) jQuery.removeEvent( elem, type, elemData.handle );를 통해 요소에 바인딩된 이벤트를 실제로 제거하고, event 객체에서 해당 이벤트에 대한 내용 삭제

1-8) 해당 요소에 바인딩된 이벤트가 모두 제거된 경우라면 캐시에서도 제거

delete events[ type ];

// Remove the expando if it's no longer usedif ( jQuery.isEmptyObject( events ) ) delete elemData.handle; dataPriv.remove( elem, "events" );

Page 30: How jQuery event works

Flow diagram: .off()

Page 31: How jQuery event works

Recapping main points실제 DOM에 바인드 되는 핸들러는 사용자 핸들러가 아닌, jQuery 핸들러가 설정된다.동일 이벤트를 여러번 바인딩 하더라도, 최초 한번만 실제로 바인딩되고 나머지는 내부에서 큐 형태로 관리된다.요소에 설정되는 이벤트 정보는 내부 캐시에 저장된다.special hook을 사용하면 특점 시점에 이벤트를 제어할 수 있다.

Page 32: How jQuery event works

Gracias[Image source] https://www.flickr.com/photos/pslee999/14539172610/