在写前端代码的时候经常会用到onmouseover 和 onmouseout事件。
如果触发事件的对象内容为单纯的文本,即:<div>comments</div>之类的元素则不会有什么问题。
但是如果在一些复杂的应用中,在对象中添加一些其他对象,即:<div><ul></ul>< /div>类型的则会出现很变态的问题。当鼠标移动到子对象上时,也会触发父对象的onmouseout事件,这显然会造成问题。如下图移过安徽或 者其他省份这个List_box 即消失 这显然不是我们想要的。
由于多次碰到这个问题了所以决定认真研究一下这个问题。
以下是收集的一些资料:
Alimama UED 对这个问题的讨论
http://ued.alimama.com/?p=51
从这里获得第一个解决方案的思路
http://topic.csdn.net/u/20080605/13/2fee4fbb-3b40-410b-8510-358818909063.html
从AS3的 target 和 currentTarget 属性获得的思路 (AS3 的核心和 js 是类似的)
http://space.flash8.net/space/?690727/action_viewspace_itemid_383030.html
我们先来看一下这个问题的原因:
网上并没有对这个问题的原因做出很完全的解释,但是可以肯定 在移动到子对象上时 浏览器已经判断为鼠标移出了父对象,即激活了onmouseout事件。这可能和js 事件层次有关,即每个对象都是可以加事件,这样必定会有事件的层次,这里就不深究了。
解决问题的主要困难:
如果不用框架来解决这个问题,将会碰到很多困难,首先对于onmouseout时间需要特殊的处理,而且对于不同的浏览器有不同的标准,这里当然包括臭名昭著的IE 和 大名鼎鼎的 Firefox。
我这里主要使用yui来解决这个问题,这样至少在一定程度上统一了浏览器的操作,简化了问题的解决。
这里有两个解决方法:
但是首先必须了解YUI的 YAHOO.util.Event.getRelatedTarget(e)方法和 YAHOO.util.Event.getTarget(e)方法
他其实对ie 和firfox的 currentTarget和target进行了封装 因为 ie和firfox 有着不同的event调用方法。
经过测试:
YAHOO.util.Event.getRelatedTarget(e) 返回的是鼠标从父对象移出,指向的子对象元素
YAHOO.util.Event.getTarget(e) 返回的是从一个子对象移到另一个对象时的子对象
基本思路是这样的当鼠标指向不包含在父对象里的子对象时 即肯定移除了父对象 则隐藏父对象
若子对象包含在父对象中不进行任何操作。
这里又会碰到一个问题 如何才能判断子对象是否包含在父对象中,在ie 下有contains方法 而在firfox 下是不支持的
第一种思路 来自(收集的第二篇文章 ):重写HTMLElement的contains方法 由于仅firfox支持HTMLElement所以代码如下:
if(typeof(HTMLElement)!=”undefined”)
HTMLElement.prototype.contains=function(obj)
{
if(obj==this) return true;
while(obj=obj.parentNode) if(obj==this) return true;
return false;
}
这样 若在ie下即不会重写这个方法。
接着的代码:
var hideProvListBox = function(e,objName)
{
if(!this.contains(YAHOO.util.Event.getRelatedTarget(e))){
document.getElementById(objName).style.display = “none”;
}
}
YAHOO.util.Event.on(”p_idr_”,”mouseout”,hideProvListBox,”p_idr_”);
第二种思路 还是用YUI解决 因为我觉得这么成熟的YUI不可能会没有解决这个问题的办法。
翻了一会儿API 发现了Dom中的一个Region工具 咋看翻译成“区域”还是有点抽象的,啥时候js 和Region挂钩了
看了看简介,发现可以判断一个区域是否包含在另一个区域中,这下就有办法了呵呵。
代码如下:
var hideProvListBox = function(e,objName)
{
if(!YAHOO.util.Region.getRegion(this).contains(YAHOO.util.Region.getRegion(YAHOO.util.Event.getRelatedTarget(e)))){
document.getElementById(objName).style.display = “none”;
}
}
YAHOO.util.Event.on(”p_idr_”,”mouseout”,hideProvListBox,”p_idr_”);
好到此这个问题告一段落,不知到是否还有更好的办法,向各位赐教。