我们知道任何浏览器捕获都是从外层到精确的节点的,所有的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的时候满足条件,调用处理。

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

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










