Extjs 实现
关于 mouseenter : 当第一次鼠标进入节点区域时触发,以后在节点区域内(子节点间)移动 时不触发。
属于 ie 的特有事件,貌似不是 w3c 标准 ,但是很有用。
extjs 3.0 对 非ie浏览器实现了这个事件,原理很简单 , 监控 mouseover 事件,只不过 当判断只是内部移动的话(触发自内部子节点冒泡过来的 ),就把该事件屏蔽掉,不再调用用户处理函数。以及利用 事件的标准属性 (IE 没有) currentTarget ,具体看见:
extjs 3.0 ext-base-debug.js 1946 行 。
这里 用 extjs 2.2.1 模拟一下 3.0 的实现。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>mouseenter测试</title>
<script type="text/javascript" src="ext-base.js"></script>
<script type="text/javascript" src="ext-core.js"></script>
<script type="text/javascript">
//<![CDATA[
window.consoleH={
log:function(str){
Ext.get("log").update(Ext.get("log").dom.innerHTML+"<br/>"+str);
Ext.get("log").dom.scrollTop=Ext.get("log").dom.scrollHeight;
}
};
Ext.onReady(function() {
var no=1;
if(Ext.isIE) {
alert("你可以利用 mouseenter 事件");
Ext.get("t1").on("mouseenter",function(be){
consoleH.log(no++ + " : enter inside currentTarget");
});
}else {
Ext.get("t1").on("mouseover",function(be){
consoleH.log(no++ + " :----------------");
//事件发生的节点
if(be.getTarget()) consoleH.log("target - "+be.getTarget().id);
else consoleH.log("target - null");
//事件处理的当前节点
if(be.browserEvent.currentTarget) consoleH.log("currentTarget - "+be.browserEvent.currentTarget.id);
else consoleH.log("currentTarget - null");
//从哪个节点移到事件发生的节点
if(be.getRelatedTarget())consoleH.log("related - "+be.getRelatedTarget().id);
else consoleH.log("getRelatedTarget - null");
if(be.browserEvent.currentTarget) {
//如果相关节点是处理节点的子节点,或者就是处理节点 ,不是第一次进入了,属于内部移动
if(be.browserEvent.currentTarget == be.getRelatedTarget() || Ext.get(be.browserEvent.currentTarget).contains(be.getRelatedTarget()))
consoleH.log(" moveinside currentTarget");
else
//恩,是第一次
consoleH.log("enter inside currentTarget");
}
});
}
});
//]]>
</script>
</head>
<body>
<div id="log" style="position:absolute;right:0;height:400px;width:300px;border:1px solid red;overflow:scroll;">
</div>
<div style="width:400px;height:400px;border:1px solid green;" id="t1">
<div style="width:200px;height:200px;border:1px solid red;" id="t2">
<div style="width:100px;height:100px;border:1px solid black;" id="t3">
</div>
</div>
</div>
</body>
</html>
同理可实现 mouseleave 事件。
jquery 实现:
思路类似,判断当前触发节点是否是自己的子节点,是的话就忽略了 !
// Checks if an event happened on an element within another element // Used in jQuery.event.special.mouseenter and mouseleave handlers var withinElement = function(event) { // Check if mouse(over|out) are still within the same parent element var parent = event.relatedTarget; // Traverse up the tree while (parent && parent != this) try { parent = parent.parentNode; } catch(e) { parent = this; } //这里判断 this 吧 if (parent != this) { // set the correct event type event.type = event.data; // handle event if we actually just moused on to a non sub-element jQuery.event.handle.apply(this, arguments); } };
鼠标系列总结:
mousedown mouseup 的发生节点可能不一样,在a节点上mousedown,然后挪动鼠标在b节点上mouseup,则a节点上触发事件 mousedown,b节点上触发事件 mouseup,故对于拖放 mouseup 应绑定在 document 上面,而不是拖放节点。
mouseover,mouseout 可能会有一些想不到的效果,比如内部嵌套节点的mouseover,mouseout 事件会冒泡到主节点的事件处理器,并不是自己想要的效果,可以根据target以及relatedTarget来判断
mousemove 每个像素的变化都会导致触发,可用定时器来减缓提高性能。