$.event.trigger的作用十分广泛,可以触发自定义事件,dom事件,独有事件,并且支持事件的传播和默认行为。同时jq的事件提供了namespace支持,这在使用trigger时候也需要注意:
1. 如果指定了namespace,就只会触发符合的事件或者其超集的事件。
2. 如果没有指定namespace,就会触发该type下的所有事件。
3. 如果没传element,会触发type下的全局事件。如$.ajax.success。
4. event path事件传播路径,最高可达到window,且不论是监听函数,还是inline函数都可以实现Propagation。
5. 有selector的事件就是代理事件,delegate event不会在同级触发。
源码附上:
trigger: function( event, data, elem, onlyHandlers ) {
// Don't do events on text and comment nodes
if ( elem && (elem.nodeType === 3 || elem.nodeType ===8) ) {
return;
}
// Event object or event type trigger('click', ...) trigger(e, ...)
var type = event.type || event,
namespaces = [],
cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType;
// 独有的事件 setData getData...
if ( type.indexOf( "!" ) >= 0 ) {
// Exclusive events trigger only for the exact event (no namespaces)
type = type.slice(0, -1);
exclusive = true;
}
// 带有namespace的事件
if ( type.indexOf( "." ) >= 0 ) {
// Namespaced trigger; create a regexp to match event type in handle()
namespaces = type.split(".");
type = namespaces.shift();
namespaces.sort();
}
if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
// No jQuery handlers for this event type, and it can't have inline handlers
return;
}
// Caller can pass in an Event, Object, or just an event type string
// 包装成jq.Event对象
event = typeof event === "object" ?
// jQuery.Event object
event[ jQuery.expando ] ? event :
// Object literal
new jQuery.Event( type, event ) :
// Just the event type (string)
new jQuery.Event( type );
event.type = type;
event.isTrigger = true;
// dispatch中用到
event.exclusive = exclusive;
event.namespace = namespaces.join( "." ); // event.handleObject.namespace
// 如果tirgger指定了namespace,就会有这个判断,否则会触发type下所有的handle
event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
// 行内handle
ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
// triggerHandler() and global events don't bubble or run the default action
if ( onlyHandlers || !elem ) {
event.preventDefault();
}
// 如果没传elem,触发cache中所有符合type的事件,ajax中全局事件会用到
if ( !elem ) {
// TODO: Stop taunting the data cache; remove global events and always attach to document
cache = jQuery.cache;
for ( i in cache ) {
if ( cache[ i ].events && cache[ i ].events[ type ] ) {
jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
}
}
return;
}
// Clean up the event in case it is being reused
event.result = undefined;
if ( !event.target ) {
event.target = elem;
}
// 创建handle的参数列表,将event作为第一个参数
data = data != null ? jQuery.makeArray( data ) : [];
data.unshift( event );
// Allow special events to draw outside the lines
special = jQuery.event.special[ type ] || {};
if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
return;
}
// 确定event的传播路径, per W3C events spec (#9951)
// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
eventPath = [[ elem, special.bindType || type ]];
// noBubble: focus、blur
if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
bubbleType = special.delegateType || type;
old = null;
for ( cur = elem.parentNode; cur; cur = cur.parentNode ) {
eventPath.push([ cur, bubbleType ]);
old = cur;
}
// 只有到达document时才加入window (e.g., not plain obj or detached DOM)
if ( old && old === elem.ownerDocument ) {
eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
}
}
// 在传播路径上触发事件处理句柄
for ( i = 0; i < eventPath.length; i++ ) {
cur = eventPath[i][0];
event.type = eventPath[i][1];
// 确定这个elem(cur)添加了事件处理函数
handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
if ( handle ) {
// 执行的是dispatch
handle.apply( cur, data );
}
// 执行inline handle
handle = ontype && cur[ ontype ];
if ( handle && jQuery.acceptData( cur ) ) {
handle.apply( cur, data );
}
// 如果停止了传播,就推出循环
if ( event.isPropagationStopped() ) {
break;
}
}
event.type = type;
// If nobody prevented the default action, do it now
if ( !event.isDefaultPrevented() ) {
if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
// 执行dom上与event同名的方法.
// Can't use an .isFunction() check here because IE6/7 fails that test.
// 不在window上执行,因为可能是全局的方法
// IE<9 不能在隐藏element上执行focus、blur (#1486)
if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
// Don't re-trigger an onFOO event when we call its FOO() method
old = elem[ ontype ];
if ( old ) {
elem[ ontype ] = null; // 阻止elem.onXXX
}
// Prevent re-triggering of the same event, since we already bubbled it above
// 防止再次触发相同的事件
jQuery.event.triggered = type; // 阻止dispatch
elem[ type ]();
jQuery.event.triggered = undefined;
if ( old ) {
elem[ ontype ] = old;
}
}
}
}
return event.result;
}
可以看出,trigger时会执行eventHandle也就是添加在dom上的监听函数$.event.dispath。这个方法针对每个event只会添加一次,它负责从$.cache中取得对应事件的所有handlers,并处理执行这些事件句柄。 (更多…)
RSS