English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
시작
jQuery가 콜백 함수를 전달하지 않아도 이벤트를 해제할 수 있는 이유는 무엇인가요? 다음과 같습니다:
$("p").on("click",function(){ alert("The paragraph was clicked."); }); $("#box1").off("click");
이벤트 바인딩 및 해제 메커니즘
on 함수를 호출할 때, 이벤트 데이터가 생성되며 구조는 다음과 같습니다:
{ type: type, origType: origType, data: data, handler: handler, guid: guid, selector: selector, needsContext: needsContext, namespace: namespace }
이 데이터를 요소의 캐시에 추가합니다. jQuery는 각 요소에 대해 캐시를 가질 수 있으며(필요할 때만 생성됩니다), 이는 실제로는 요소의 하나의 속성입니다. jQuery는 각 요소의 각 이벤트에 대해 큐를 만들어 이벤트 처리 함수를 저장하므로, 요소에 여러 이벤트 처리 함수를 추가할 수 있습니다. 캐시 구조는 다음과 같습니다:
"div#box":{ //요소 "Jquery623873:{ //요소의 캐시 "events":{ "click":[ { //요소 클릭 이벤트의 이벤트 데이터 type: type, origType: origType, data: data, handler: handler, guid: guid, selector: selector, needsContext: needsContext, namespace: namespace } ], "mousemove":[ { type: type, origType: origType, data: data, handler: handler, guid: guid, selector: selector, needsContext: needsContext, namespace: namespace } ] } } }
이벤트를 해제할 때, fn 파라미터를 지정하지 않으면 jQuery는 요소의 캐시에서 해제할 이벤트의 처리 함수 퀸트를 가져와 fn 파라미터를 꺼내서 removeEventListener을 호출하여 해제합니다.
원본 코드
코드 주석은 명확하지 않을 수 있으므로 복사하여 확인하세요.
jQuery 프로토타입의 on, one, off 메서드:
이벤트 바인딩은 여기서 시작됩니다.
jQuery.fn.extend({ on: function(types, selector, data, fn) { return on(this, types, selector, data, fn); }, one: function(types, selector, data, fn) { return on(this, types, selector, data, fn, 1 ); }, off: function(types, selector, fn) { //파라미터 처리 코드는 여기서 생략됩니다. return this.each(function() { jQuery.event.remove(this, types, fn, selector); }); } });
one과 on이 호출할 수 있는 독립적인 on 함수:
function on(elem, types, selector, data, fn, one) { var origFn, type; //파라미터 처리 코드는 여기서 생략됩니다. //one으로 바인딩된 것이면, 현재 이벤트 콜백 함수에 대한 함수 대리자를 사용하며, 대리 함수는 한 번만 실행됩니다. //여기서 중계 모델이 사용되었습니다. if (one === 1 ) { origFn = fn; fn = function(event) { // event에 정보가 포함되어 있기 때문에 빈 집합을 사용할 수 있습니다. jQuery().off(event); return origFn.apply(this, arguments); }; // 동일한 guid를 사용하여 호출자가 origFn을 사용하여 제거할 수 있도록 합니다. fn.guid = origFn.guid || (origFn.guid = jQuery.guid);++ ); } /************************************************ *** jQuery는 모든 선택된 요소를 배열에 담아두고, 그 다음 *** 각 요소에 이벤트 객체의 add 메서드를 사용하여 이벤트를 바인딩합니다. *************************************************/ return elem.each(function() { jQuery.event.add(this, types, fn, data, selector); }); }
파라미터를 처리하는 코드도 확인할 수 있습니다. on("click", function() {})와 같은 호출을 구현합니다. on: function(types, selector, data, fn)도 오류 없이 작동합니다. 실제로는 내부에서 data, fn 파라미터가 비어 있을 때 selector를 fn에 할당하는 것입니다.
이벤트 객체는 이벤트 바인딩의 핵심 객체입니다:
이곳에서 이벤트를 요소에 바인딩하고 요소 캐시에 이벤트 정보를 추가하는 작업을 처리합니다:
jQuery.event = { add: function(elem, types, handler, data, selector) { var handleObjIn, eventHandle, tmp, 이벤트, t, handleObj, 특별한 핸들러, 핸들러, 타입, 네임스페이스, 원래 타입, elemData = dataPriv.get(elem); //이 문장은 elem이 캐시되어 있는지 확인하고, 캐시되지 않았다면 elem 요소에 캐시를 추가합니다. 형식은 elem["jQuery"]와 같습니다.310057655476080253721"] = {}; // noData나 텍스트에 이벤트를 연결하지 마세요./비주얼 노드(하지만 평범한 객체를 허용) if (!elemData) { return; } //사용자는 이벤트 콜백 함수 대신 사용자 정의 데이터 객체를 입력할 수 있으며, 이벤트 콜백 함수를 이 데이터 객체의 handler 속성에 배치할 수 있습니다. if (handler.handler) { handleObjIn = handler; handler = handleObjIn.handler; selector = handleObjIn.selector; } //각 이벤트 콜백 함수는 유일한 ID를 생성합니다. 이후 find에 사용됩니다./remove할 때 사용됩니다. if (!handler.guid) { handler.guid = jQuery.guid++; } // 요소가 첫 번째 이벤트를 바인딩할 때, 요소의 이벤트 데이터 구조와 메인 콜백 함수(main)을 초기화합니다. //설명: 각 요소에 메인 콜백 함수가 있으며, 여러 이벤트를 이 요소에 바인딩할 때 콜백의 진입점으로 사용됩니다 if ( !( events = elemData.events ) ) { events = elemData.events = {}; } //여기가 메인 콜백 함수를 초기화하는 코드입니다 if ( !( eventHandle = elemData.handle ) ) { eventHandle = elemData.handle = function( e ) { // jQuery.event.trigger()의 두 번째 이벤트를 버리고 // 페이지가 로드되지 않은 후 이벤트가 호출되면 return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? jQuery.event.dispatch.apply( elem, arguments ) : undefined; }; } // 이벤트 바인딩을 처리할 때, 여러 이벤트가 공백으로 구분되어 입력될 수 있으므로, 여러 이벤트 처리를 수행합니다 types = ( types || "" ).match( rnotwhite ) || [ "" ]; t = types.length; while ( t-- ) { tmp = rtypenamespace.exec( types[ t ] ) || []; type = origType = tmp[ 1 ]); namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); // There *절대로* 타입이어야 하며, 네임스페이스를 연결하지 않습니다-제어자만 if ( !type ) { 계속; } // 이벤트가 타입을 변경하면 변경된 타입의 특별한 이벤트 핸들러를 사용합니다 special = jQuery.event.special[type] || {}; // 선택자가 정의되어 있으면 특별한 이벤트 api 타입을 결정합니다. 그렇지 않으면 주어진 타입을 사용합니다 type = (selector ? special.delegateType : special.bindType) || type; // Update special based on newly reset type special = jQuery.event.special[type] || {}; // Data object of event callback function handleObj = jQuery.extend({ type: type, origType: origType, data: data, handler: handler, guid: handler.guid, selector: selector, needsContext: selector && jQuery.expr.match.needsContext.test(selector), namespace: namespaces.join(".") }, handleObjIn); // If this is the first time to bind this type of event, an array will be initialized as the event callback function queue, and each element of each event has a queue if (!(handlers = events[type])) { handlers = events[ type ] = []; handlers.delegateCount = 0; // Only use addEventListener if the special events handler returns false if (!special.setup || special.setup.call(elem, data, namespaces, eventHandle) === false) if (elem.addEventListener) { elem.addEventListener(type, eventHandle); } } } if (special.add) { special.add.call(elem, handleObj); if (!handleObj.handler.guid) { handleObj.handler.guid = handler.guid; } } // 이벤트 콜백 함수 퀸에 추가합니다 if ( selector ) { handlers.splice( handlers.delegateCount++, 0, handleObj ); } else { handlers.push( handleObj ); } // 사용된 적 있는 이벤트를 추적하여 이벤트 최적화에 사용합니다 // 이벤트를 최적화하기 위해 사용되지 않은 이벤트를 추적하는 데 사용됩니다 jQuery.event.global[ type ] = true; } } };
매우 주의하십시오, 객체와 배열은 참조를 전달합니다! 예를 들어, 이벤트 데이터를 캐시에 저장하는 코드:
handlers = events[ type ] = []; if ( selector ) { handlers.splice( handlers.delegateCount++, 0, handleObj ); } else { handlers.push( handleObj ); }
handlers의 변경, events[ type ]는 동시에 변경됩니다.
dataPriv는 캐시를 관리하는 객체입니다:
그 작업은 요소에 속성을 생성하고, 이 속성이 객체이며, 이 요소와 관련된 정보를 이 객체에 넣고 캐시하는 것입니다. 이렇게 해서 이 객체의 정보를 사용할 필요가 있을 때, 이 객체만 알면 이를 가져올 수 있습니다:
function Data() { this.expando = jQuery.expando + Data.uid++; } Data.uid = 1; //사용하지 않은 일부 코드를 제거합니다 Data.prototype = { cache: function( 소유자 ) { // 캐시를 꺼내서, 캐시는 목표 객체의 하나의 속성입니다 var 값 = 소유자[ this.expando ]; // 객체가 캐시되지 않았다면, 하나를 생성하십시오 if ( !값 ) { 값 = {}; // 비 소유자 데이터를 받아들이면 됩니다-현대 브라우저의 요소 노드들에 대해 // 하지만 우리는 그렇지 않아야 합니다, see #8335. // 빈 객체를 항상 반환하십시오. if ( acceptData( 소유자 ) ) { // 문자열로 변환할 가능성이 낮은 노드라면-거나 반복됩니다 // 플랫 assign 사용하십시오 if ( owner.nodeType ) { 소유자[ this.expando ] = 값; // 그렇지 않으면 그것을 비활성화 상태로 보안하게 하십시오-enumerable property // configurable must be true to allow the property to be // deleted when data is removed } else { Object.defineProperty( owner, this.expando, { value: value, configurable: true }); } } } return value; }, get: function( owner, key ) { return key === undefined ? this.cache( owner ) : // Always use camelCase key (gh-2257) 驼峰命名 owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; }, remove: function( owner, key ) { var i, cache = owner[ this.expando ]; if ( cache === undefined ) { return; } if ( key !== undefined ) { // Support array or space separated string of keys if ( jQuery.isArray( key ) ) { // If key is an array of keys... // We always set camelCase keys, so remove that. key = key.map( jQuery.camelCase ); } else { key = jQuery.camelCase( key ); // If a key with the spaces exists, use it. // Otherwise, create an array by matching non-whitespace key = key in cache ? [ key ] : ( key.match( rnotwhite ) || [] ); } i = key.length; while ( i-- ) { delete cache[ key[ i ] ]; } } // 데이터가 더 이상 없을 경우 expando를 제거합니다 if ( key === undefined || jQuery.isEmptyObject( cache ) ) { // 지원: Chrome <=35 - 45 // 프로퍼티를 제거할 때 Webkit & Blink 성능이 저하됩니다 // from DOM nodes, so set to undefined instead // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) if ( owner.nodeType ) { owner[ this.expando ] = undefined; } else { delete owner[ this.expando ]; } } }, hasData: function( owner ) { var cache = owner[ this.expando ]; return cache !== undefined && !jQuery.isEmptyObject( cache ); } };
이것이 본 문서의 전체 내용입니다. 이를 통해 여러분의 학습에 도움이 되길 바라며,呐喊 튜토리얼에 많은 지지를 부탁드립니다.
명시: 본 내용은 인터넷에서 수집되었으며, 저작권은 원 저작자에게 있으며, 인터넷 사용자가 자발적으로 기여하고 업로드한 내용입니다. 이 사이트는 저작권을 소유하지 않으며, 인공 편집 처리를 하지 않았으며, 관련 법적 책임을 부담하지 않습니다. 저작권 침해 내용이 있을 경우, notice#w로 이메일을 보내 주시기 바랍니다.3codebox.com에 (이메일 보내기 시, #을 @으로 변경하여) 신고를 해 주시고 관련 증거를 제공해 주시면, 사실이 확인되면 이 사이트는 즉시 저작권 침해 내용을 삭제할 것입니다.