您的位置:首页 > Web前端 > JQuery

jQuery的on方法

2016-04-22 19:41 441 查看
jQuery中on方法的使用

// eg1
$('.target').on('click', function(){
console.log(this);
});
// eg2
$(document).on('click', '.target', function(){
console.log(this);
});


上面的两种使用方式都是可以的:

第一种是直接给页面中class中含有target的元素绑定上click事件;

第二种是把事件绑定在document上,然后判断当前的目标元素是否是class中含有target的元素进而来执行相应的事件(这种方式绑定上的事件,对之后动态添加的元素也同样有效果,通过事件冒泡来实现该操作)。

jQuery如何实现on方法的呢?

jQuery源码是这样写的:

// on
on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
......
//省略部分代码(前面的代码是对传入的参数做一些处理)
......
return this.each( function() {
// 调用jQuery.event.add方法
jQuery.event.add( this, types, fn, data, selector );
});
}

// 调用jQuery.event.add方法
add: function( elem, types, handler, data, selector ) {
......
if ( !eventHandle ) {
// 设置事件句柄方法
elemData.handle = eventHandle = 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" && (!e || jQuery.event.triggered !== e.type) ?
// 事件句柄的回调函数
// eventHandle.elem 事件对象
// arguments 传递的参数
jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
undefined;
};
// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
eventHandle.elem = elem;
}
......
// 绑定了一个或多个方法
for ( t = 0; t < types.length; t++ ) {

tns = rtypenamespace.exec( types[t] ) || [];
type = tns[1];
namespaces = ( tns[2] || "" ).split( "." ).sort();

// If event changes its type, use the special event handlers for the changed type
special = jQuery.event.special[ type ] || {};

// If selector defined, determine special event api type, otherwise given type
type = ( selector ? special.delegateType : special.bindType ) || type;

// Update special based on newly reset type
special = jQuery.event.special[ type ] || {};

// handleObj is passed to all event handlers
// 将一些数据信息放到handleObj中
handleObj = jQuery.extend({
type: type,
origType: tns[1],
data: data,
handler: handler,
guid: handler.guid,
selector: selector,
needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
namespace: namespaces.join(".")
}, handleObjIn );

// Init the event handler queue if we're the first
handlers = events[ type ];
if ( !handlers ) {
handlers = events[ type ] = [];
handlers.delegateCount = 0;

// Only use addEventListener/attachEvent if the special events handler returns false
if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
// Bind the global event handler to the element
// 绑定上事件
if ( elem.addEventListener ) {
elem.addEventListener( type, eventHandle, false );
} else if ( elem.attachEvent ) {
elem.attachEvent( "on" + type, eventHandle );
}
}
}

if ( special.add ) {
special.add.call( elem, handleObj );

if ( !handleObj.handler.guid ) {
handleObj.handler.guid = handler.guid;
}
}

// Add to the element's handler list, delegates in front
if ( selector ) {
handlers.splice( handlers.delegateCount++, 0, handleObj );
} else {
handlers.push( handleObj );
}
// console.log(handlers);

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

// 调用jQuery.event.dispatct方法
dispatch: function( event ) {
......
if ( delegateCount && !(event.button && event.type === "click") ) {
// 遍历元素
for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
// Don't process clicks (ONLY) on disabled elements (#6911, #8165, #11382, #11764)
if ( cur.disabled !== true || event.type !== "click" ) {
selMatch = {};
matches = [];
for ( i = 0; i < delegateCount; i++ ) {
handleObj = handlers[ i ];
sel = handleObj.selector;

if ( selMatch[ sel ] === undefined ) {
selMatch[ sel ] = handleObj.needsContext ?
jQuery( sel, this ).index( cur ) >= 0 :
jQuery.find( sel, this, null, [ cur ] ).length;
}
// 将符合的元素事件数据对象放进matches中
if ( selMatch[ sel ] ) {
matches.push( handleObj );
}
}
// 将matches和当前对象放到handlerQueue中
if ( matches.length ) {
handlerQueue.push({ elem: cur, matches: matches });
}
}
}
}
......

// Run delegates first; they may want to stop propagation beneath us
// 遍历handlerQueue,里面是符合条件的数据对象
for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
matched = handlerQueue[ i ];
event.currentTarget = matched.elem;

for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
handleObj = matched.matches[ j ];

// Triggered event must either 1) be non-exclusive and have no namespace, or
// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {

event.data = handleObj.data;
event.handleObj = handleObj;

// 执行我们调用on方法时所写的回调函数。
ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
.apply( matched.elem, args );

// console.log(ret);

if ( ret !== undefined ) {
event.result = ret;
if ( ret === false ) {
event.preventDefault();
event.stopPropagation();
}
}
}
}
}

}


jQuery中的
one
,
bind
,
live
,
delegate
都是基于
on
方法来改造的。

// one
one: function( types, selector, data, fn ) {
return this.on( types, selector, data, fn, 1 );
},
// bind
bind: function( types, data, fn ) {
return this.on( types, null, data, fn );
},
// live
live: function( types, data, fn ) {
jQuery( this.context ).on( types, this.selector, data, fn );
return this;
},
// delegate
delegate: function( selector, types, data, fn ) {
return this.on( types, selector, data, fn );
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: