jQuery 1.9.1源码分析系列(十)事件系统之主动触(3)

  我们知道任何浏览器捕获都是从外层到精确的节点的,所有的focusin事件都会被捕获到,然后执行handler函数(里面是jQuery.event.simulate函数,源码略)。其他事件绑定则进入if分支将事件直接绑定到elem上

if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {   if ( elem.addEventListener ) {     elem.addEventListener( type, eventHandle, false );   } else if ( elem.attachEvent ) {     elem.attachEvent( "on" + type, eventHandle );   } }

special第二组:mouseenter/mouseleave

//使用mouseover/out和事件时机检测创建mouseenter/leave事件 jQuery.each({ mouseenter: "mouseover", mouseleave: "mouseout" }, function( orig, fix ) { jQuery.event.special[ orig ] = { delegateType: fix, bindType: fix, handle: function( event ) { var ret, target = this, related = event.relatedTarget, handleObj = event.handleObj; //对于mousenter/leave,当related在target外面的时候才调用handler //参考: 当鼠标离开/进入浏览器窗口的时候是没有relatedTarget的 if ( !related || (related !== target && !jQuery.contains( target, related )) ) { event.type = handleObj.origType; ret = handleObj.handler.apply( this, arguments ); event.type = fix; } return ret; } }; });

  需要注意的是只有在鼠标指针穿过被选元素时,才会触发 mouseenter 事件。对应mouseleave这样的话,mouseenter子元素不会反复触发事件,否则在IE中经常有闪烁情况发生

  使用mouseover/out和事件时机检测创建mouseenter/leave事件有个关键的判断

if ( !related || (related !== target && !jQuery.contains( target, related )) )

  其中!jQuery.contains( target, related )表示related在target外面。我们使用图例来解释

  我们假设处理的是mouseenter事件,进入target。

  鼠标从related到target,很明显related在target外面,所以当鼠标移动到target的时候满足条件,调用处理。

  

jQuery 1.9.1源码分析系列(十)事件系统之主动触

  现在反过来,很明显related在target里面,那么鼠标之前就处于mouseenter状态(意味着之前就进行了mouseenter处理器处理),避免重复调用当然是不进行任何处理直接返回了。

  

jQuery 1.9.1源码分析系列(十)事件系统之主动触

  我们假设处理的是mouseleave事件,离开target。

  鼠标从target到related,很明显related在target里面,所以当鼠标移动到related的时候依然么有离开target,不做处理。

  

jQuery 1.9.1源码分析系列(十)事件系统之主动触

  鼠标从target到related,很明显related在target外面,所以当鼠标移动到related的时候已经离开了target的范围,做处理。

  

jQuery 1.9.1源码分析系列(十)事件系统之主动触

special第三组:submit和change

主要是ie下submit不能冒泡的处理

  jQuery.event.special.submit主要有一下几个特征

  setup
  postDispatch
  teardown

  根据添加事件的代码可知添加事件的时候如果符合条件则会调用setup来添加事件

if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false )

  jQuery在ie下模拟submit事件以click和keypress替代,只不过是添加了命名空间来区别和普通click和keypress事件。

setup: function() {   ...   jQuery.event.add( this, "click._submit keypress._submit", function( e ) {     var elem = e.target,     form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;       if ( form && !jQuery._data( form, "submitBubbles" ) ) {         jQuery.event.add( form, "submit._submit", function( event ) {           event._submit_bubble = true;         });         jQuery._data( form, "submitBubbles", true );       }   }); },

  在事件调用过程中(dispatch)会调用postDispatch来处理

if ( special.postDispatch ) { special.postDispatch.call( this, event ); }   postDispatch中调用simulate完成事件处理 postDispatch: function( event ) {   // If form was submitted by the user, bubble the event up the tree   if ( event._submit_bubble ) {     delete event._submit_bubble;     if ( this.parentNode && !event.isTrigger ) {       jQuery.event.simulate( "submit", this.parentNode, event, true );     }   } },

  teardown用在删除事件绑定中

  ie下change事件的处理和submit类似,事件使用beforeactivate替代来监听,处理函数变成了handle,在事件分发(dispatch)中执行代码

ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )     .apply( matched.elem, args ); 

主要源码如下

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgzdxz.html