跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

读jQuery之十四 (触发事件核心方法)_jquery

在 事件模块的演变 我使用了dispatchEvent(标准) 和fireEvent(IE)来主动触发事件。如下复制代码代码如下:...

dispatch = w3c ?function(el, type){try{var evt = document.createEvent('Event');evt.initEvent(type,true,true);el.dispatchEvent(evt);}catch(e){alert(e)};} :function(el, type){try{el.fireEvent('on'+type);}catch(e){alert(e)}};...

jQuery则完全没有用到dispatchEvent/fireEvent方法。它采用的是另外一种机制。

jQuery触发事件的核心方法是jQuery.event.trigger。它提供给客户端程序员使用的触发事件方法有两个:.trigger/.triggerHandler一个事件的发生在某些元素中可能会导致两种动作,一个是默认行为,一个是事件handler。如链接A新浪邮箱点击后,弹出1(事件handler),点确定跳转(默认行为)到了mail.sina.com.cn。因此,设计的触发事件的函数要考虑到这两种情况。

jQuery使用.trigger和.triggerHandler区分了这两种情况:.trigger 执行事件hanlder/执行冒泡/执行默认行为.triggerHandler 执行事件handler/不冒泡/不执行默认行为复制代码代码如下:.trigger/.triggerHandler的源码如下trigger: function( type, data ) {return this.each(function() {jQuery.event.trigger( type, data, this );});},triggerHandler: function( type, data ) {if ( this[0] ) {return jQuery.event.trigger( type, data, this[0], true );}},可以看出,两者都调用jQuery.event.trigger。调用时一个没有传true,一个传了。传了true的triggerHander就表示仅执行事件handler。

此外还需注意一点区别:.trigger是对jQuery对象集合的操作,而.triggerHandler仅操作jQuery对象的第一个元素。如下复制代码代码如下:p1 p1 p1好了,是时候贴出jQuery.event.trigger的代码了复制代码代码如下:trigger: function( event, data, elem, onlyHandlers ) {// Event object or event type var type = event.type || event,namespaces = [],exclusive;......

}这就是jQuery.event.trigger的定义,省略了大部分。下面一一列举复制代码代码如下:if ( type.indexOf("!") >= 0 ) {// Exclusive events trigger only for the exact event (no namespaces) type = type.slice(0, -1);exclusive = true;}这一段是为了处理.trigger('click!')的情形,即触发非命名空间的事件。变量exclusive挂在事件对象上后在jQuery.event.handle内使用。举个例子复制代码代码如下:function fn1() {console.log(1)}function fn2() {console.log(2)}$(document).bind('click.a', fn1);$(document).bind('click', fn2);$(document).trigger('click!'); // 2为document添加了两个点击事件,一个是具有命名空间的"click.a",一个则没有"click"。使用trigger时参数click后加个叹号"!"。从输出结果为2可以看出不触发命名空间的事件。总结一下:.trigger('click') 触发所有的点击事件.trigger('click.a') 仅触发“click.a” 的点击事件.trigger('click!') 触发非命名空间的点击事件接着看复制代码代码如下:if ( type.indexOf(".") >= 0 ) {// Namespaced trigger; create a regexp to match event type in handle() namespaces = type.split(".");type = namespaces.shift();namespaces.sort();}这段就很好理解了,就是对.trigger('click.a')的处理,即对具有命名空间事件的处理。

接着看复制代码代码如下: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;}对于一些特殊事件如"getData"或对于已经触发过的事件直接返回。

往下复制代码代码如下: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 本身就是jQuery.Event类的实例,event是个普通js对象(非jQuery.Event类的实例)

,event是个字符串,如"click"续event.type = type;event.exclusive = exclusive;event.namespace = namespaces.join(".");event.namespace_re = new RegExp("(^|\.)" + namespaces.join("\.(?:.*\.)?") + "(\.|$)");需要注意exclusive/namespace/namespace_re挂到了event上了,在jQuery.event.handle中可以用到(事件命名空间)。

往下是复制代码代码如下:// triggerHandler() and global events don't bubble or run the default action if ( onlyHandlers || !elem ) {event.preventDefault();event.stopPropagation();}onlyHandlers 只在 .triggerHandler用到了,即不触发元素的默认行为,且停止冒泡。

下面是复制代码代码如下:// Handle a global trigger if ( !elem ) {// TODO: Stop taunting the data cache; remove global events and always attach to document jQuery.each( jQuery.cache, function() {// internalKey variable is just used to make it easier to find// and potentially change this stuff later; currently it just// points to jQuery.expando var internalKey = jQuery.expando,internalCache = this[ internalKey ];if ( internalCache && internalCache.events && internalCache.events[ type ] ) {jQuery.event.trigger( event, data, internalCache.handle.elem );}});return;}这里是个递归调用。如果没有传elem元素,那么从jQuery.cache里取。

接着是复制代码代码如下:// Don't do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) {return;}属性,文本节点直接返回。

下面是复制代码代码如下:// Clone any incoming data and prepend the event, creating the handler arg list data = data != null ? jQuery.makeArray( data ) : [];data.unshift( event );先将参数data放入数组,event对象放在数组的第一个位置。

接着是复制代码代码如下:// Fire event on the current element, then bubble up the DOM tree do {var handle = jQuery._data( cur, "handle" );event.currentTarget = cur;if ( handle ) {handle.apply( cur, data );}// Trigger an inline bound script if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) {event.result = false;event.preventDefault();}// Bubble up to document, then to window cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window;} while ( cur && !event.isPropagationStopped() );这段代码很重要,做了以下事情,取handle,执行,执行通过onXXX方式添加的事件(如onclick="fun()")

,取父元素while循环不断重复这四步以模拟事件冒泡。直到window对象。

接下是复制代码代码如下:// If nobody prevented the default action, do it now if ( !event.isDefaultPrevented() ) {var old,special = jQuery.event.special[ type ] || {};if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) &&!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {// Call a native DOM method on the target with the same name name as the event.

// Can't use an .isFunction)() check here because IE6/7 fails that test.

// IEtry {if ( ontype && elem[ type ] ) {// Don't re-trigger an onFOO event when we call its FOO() method old = elem[ ontype ];if ( old ) {elem[ ontype ] = null;}jQuery.event.triggered = type;elem[ type ]();}} catch ( ieError ) {}if ( old ) {elem[ ontype ] = old;}jQuery.event.triggered = undefined;}}这一段是对于浏览器默认行为的触发。如form.submit(),button.click()等。

注意,由于Firefox中链接的安全性限制,jQuery对链接的默认行为都统一为不能触发。即不能通过.trigger()使链接跳转。

相关文章