解决HTML内部元素的Mouse事件干扰

话说有一个DIV元素,其内部有一个IMG元素和SPAN元素,不用理会这两个内部元素怎么布局,这不是我要讨论的重点。

为了实现一些特殊的效果,我需要利用TD的onmouseover和onmouseout事件,测试时就会发现如下的状况:
当鼠标移入DIV内部时,onmouseover事件被触发;接着再鼠标移动到DIV内部的IMG或者SPAN元素之上,我们肯定不会认为这时鼠标已经移到了DIV的外边,但奇怪的是onmouseout事件触发了,而且紧接着onmouseover事件也马上被触发了。

这可不是我想要的,那么怎么来“屏蔽”内部元素给外层元素带来的Javascript事件干扰呢?

这里列举两种方法:

一. setTimeout

因为在鼠标移动到内部元素之上而触发了外层元素的onmouseout事件后,外层元素的onmouseover也会马上触发,所以我们只需要把外层元素的onmouseout事件需要执行的动作延迟很短的一段时间来运行,然后在onmouseover事件中再执行clearTimeout方法,这样就可以避免内部元素引起的事件干扰。

具体的执行过程请看下图(纵向的虚线表示时间):

这是个很巧妙的的方法,因为当onmouseout触发后,实质性的方法并没有马上执行,而是要等待一小段时间。如果在这段时间里马上又触发了onmouseover事件,那么基本上就可以肯定onmouseout事件的触发是因为内部元素的干扰了,所以在onmouseover事件中使用clearTimeout来阻止延时的方法执行。

二.contains

在onmouseover时先进行如下判断,结果为true时再执行方法体:

if(!this.contains(event.fromElement)){MouseOverFunc()}

在onmouseout时先进行如下判断,结果为true时再执行方法体:

if(!this.contains(event.toElement)){MouseOutFunc()}

下面来解释一下上面两行代码的含义:

在IE中,所有的HTML元素都有一个contains方法,它的作用是判断当前元素内部是否包含指定的元素。我们利用这个方法来判断外层元素的事件是不是因为内部元素而被触发,如果内部元素导致了不需要的事件被触发,那我们就忽略这个事件。

event.fromElement指向触发onmouseover和onmouseout事件时鼠标离开的元素;event.toElement指向触发onmouseover和onmouseout事件时鼠标进入的元素。

那么上面两行代码的含义就分别是:

○ 当触发onmouseover事件时,判断鼠标离开的元素是否是当前元素的内部元素,如果是,忽略此事件;

○ 当触发onmouseout事件时,判断鼠标进入的元素是否是当前元素的内部元素,如果是,忽略此事件;

这样,内部元素就不会干扰外层元素的onmouseover和onmouseout事件了。

但问题又来了,非IE的浏览器并不支持contains函数,不过既然我们已经知道了contains函数的作用,就可以自行添加如下的代码来为非IE浏览器增加contains支持:

if(typeof(HTMLElement) != "undefined")
{
HTMLElement.prototype.contains = function(obj)
{
while(obj != null && typeof(obj.tagName) != "undefind")
{
if(obj == this)
Return true;
Obj = obj.parentNode;}
return false;
};
}

18 Comments

  1. 真心人

    其��这些从JavaScript中都可以得到答案,JavaScript书中的一个知识点:事件冒泡

  2. 无独有偶! 我也刚刚解决了这个问题。

    首先,出现这种情况是因为事件冒泡,<span>触发事件后将事件向上
    传给<div>, 在我的例子里面,还多了一层。

    解决办法:
    在事件处理函数中首先判断当��元素是否为<div>元素,
    如果不是,则向上检查容器节点直到元素匹配为止。
    node = node.parentNode;
    期间不需理会兄弟节点等,只需一直向上寻找。

  3. @请输入你的姓名
    @Jacky Zhong
    @真心人
    其实这篇文章想要讲的并不是事件冒泡的问题,时间冒泡是从内部元素传递事件到外部元素,而我所描述的情况是因为内部元素触发了外部元素的事件。
    如果在内部元素的事件中作判断,显然已经迟了,因为外部元素的onmouseout已经被触发了,而我的目的是组织内部元素引发的外部元素的onmouseout。
    所以显然event.cancelBubble并不能解决这种问题,因为外部元素的onmouseout事件要比内部元素的onmouseover事件先触发。

  4. [汉族]

    对于 mouseover,mouseout 事件,它的区域 并不包括内部元素的区域,如果需要内部元素 事件 影响外部就开启 事件冒泡,反之 关闭

发表评论

电子邮件地址不会被公开。 必填项已用*标注