现在我们来看看事件机制中的主动触发,我们要分析的是jQuery.event.trigger。
先来看看它在jQ源码中的调用。
// 1, 在jQuery.event.simulate中 jQuery.event.simulate = function(){ ... if ( bubble ) { jQuery.event.trigger( e, null, elem ); } ... } // 2, 事件的实例方法中 jQuery.fn.extend({ trigger: function( type, data ) { return this.each(function() { jQuery.event.trigger( type, data, this ); }); }, triggerHandler: function( type, data ) { var elem = this[0]; if ( elem ) { return jQuery.event.trigger( type, data, elem, true ); } } }) // 3, ajax中也有主动触发 jQuery.event.trigger("ajaxStart"); jQuery.event.trigger("ajaxStop");
看到其调用,我们能猜出其参数,有4个。
来看源码:
/* type: 事件的类型 data: 事件传递的参数 elem: 绑定事件的元素 onlyHandler: 是否冒泡和触发默认事件 */ trigger: function( event, data, elem, onlyHandlers ) { var i, cur, tmp, bubbleType, ontype, handle, special, eventPath = [ elem || document ], //event支持对象的写法, 比如{"type": "click"} type = core_hasOwn.call( event, "type" ) ? event.type : event, namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; cur = tmp = elem = elem || document; // 如果是文本节点和注释节点,return; if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } // focus/blur morphs to focusin/out; ensure we're not firing them right now if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { return; } //如果有命名空间,重新得到type和namepaces if ( type.indexOf(".") >= 0 ) { // Namespaced trigger; create a regexp to match event type in handle() namespaces = type.split("."); type = namespaces.shift(); namespaces.sort(); } // 得到ontype。&&的 用法, 如果type不含有':', 比如type='click', ontype = 'onclick', 否则ontype = false ontype = type.indexOf(":") < 0 && "on" + type; // 构建或得到event对象 event = event[ jQuery.expando ] ? event : new jQuery.Event( type, typeof event === "object" && event ); // 以下都是构建event实例方法 event.isTrigger = onlyHandlers ? 2 : 3; event.namespace = namespaces.join("."); event.namespace_re = event.namespace ? new RegExp( "(^|\.)" + namespaces.join("\.(?:.*\.|)") + "(\.|$)" ) : null; event.result = undefined; if ( !event.target ) { event.target = elem; } // 初始化data data = data == null ? [ event ] : jQuery.makeArray( data, [ event ] ); // Allow special events to draw outside the lines special = jQuery.event.special[ type ] || {}; if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { return; } // Determine event propagation path in advance, per W3C events spec (#9951) // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) // 得到冒泡的路径eventPath, 如,[div, h3, body, html, Document] if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { bubbleType = special.delegateType || type; if ( !rfocusMorph.test( bubbleType + type ) ) { cur = cur.parentNode; } for ( ; cur; cur = cur.parentNode ) { eventPath.push( cur ); tmp = cur; } // Only add window if we got to document (e.g., not plain obj or detached DOM) if ( tmp === (elem.ownerDocument || document) ) { eventPath.push( tmp.defaultView || tmp.parentWindow || window ); } } // Fire handlers on the event path i = 0; while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { event.type = i > 1 ? bubbleType : special.bindType || type; //得到父元素的handle handle = ( data_priv.get( cur, "events" ) || {} )[ event.type ] && data_priv.get( cur, "handle" ); // 存在则执行handle if ( handle ) { handle.apply( cur, data ); } // 调用的是元素绑定的时间 handle = ontype && cur[ ontype ]; if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) { event.preventDefault(); } } event.type = type; // If nobody prevented the default action, do it now if ( !onlyHandlers && !event.isDefaultPrevented() ) { if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) && jQuery.acceptData( elem ) ) { if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { // 得到行内绑定的方法 tmp = elem[ ontype ]; //对行内绑定到的方法制空 if ( tmp ) { elem[ ontype ] = null; } // 执行 jQuery.event.triggered = type; elem[ type ](); jQuery.event.triggered = undefined; //重新绑定回去 if ( tmp ) { elem[ ontype ] = tmp; } } } } return event.result; },
主要流程就是取得data缓存数据,根据是否冒泡去执行相应的方法。