鼠标悬停(和离开)元素(或其子元素)时运行动作

时间:2009-11-04 15:28:18

标签: javascript dom javascript-events mouseover

想象一下,我有以下几个要素:

+------------------+
|                  |
|    +----------------+
|    |                |
|    |                |
|    +----------------+
|                  |
+------------------+

内部元素具有定位意味着它可以在视觉上坐在其父元素之外,并且我在父元素上放置了一个事件监听器,如下所示:

parent.addEventListener('mouseover', function(e) {
  // log mouse is over me
}, false);

如果我直接从底部直接鼠标上方,我会得到一个直接事件,但由于事件路由,如果我从侧面鼠标移过(先击中孩子),我也会收到来自孩子的事件它起泡了。

如果我继续向左走,直到我离开子元素并在父空间中,我将得到一个直接事件,如果我再次向右移动,我将从子元素中获得另一个冒泡事件。 / p>

这是设计,设计绝对正常,但是如果我想在鼠标悬停在我身边时做一个单一的动作(包括我的孩子项目),我需要做一些额外的工作来阻止事件我不是感兴趣...例如,这将起作用:

var isOver = false;

parent.addEventListener('mouseover', function(e) {
  if (isOver) return;
  isOver = true;
  // log mouse is over me
}, false);

parent.addEventListener('mouseout', function(e) {
  if (e.relatedTarget == this || e.relatedTarget.isDescendantOf(this)) return;
  isOver = false;
  // log mouse is leaving me
}, false);

本质上,代码有一个状态变量来确定鼠标是否已经“超过”父项(通过其子项或不通过子项),如果事件在“过度”时再次触发,则忽略这些事件。我们还捕获了鼠标输出事件并询问它..是相关目标(您即将进入的目标)ME? (父母),还是ME的最终孩子?如果是这样,那么就不要做任何事情......否则将'overed'状态设置为false。

所以代码实际上有效,但想象我不能使用relatedTarget属性来确定下一个目标,你会怎么做这个行为?

我希望这是有道理的,我觉得事件中没有足够的上下文没有relatedTarget但是觉得可能有一个关于改变eventPhase属性的行为的角度(以确定事件是直接的还是冒泡的)。

此外,我不是在寻找答案,说'这不会起作用,即yadda yadda'。我现在正在努力反对w3c事件规范浏览器。

提前致谢, 斯蒂芬。


编辑,只是为了澄清,我希望事件发生,好像我有一个看起来像这样的元素(如果元素实际上是上面的例子):

+------------------+
|                  |
|                  +--+
|                     |
|                     |
|                  +--+
|                  |
+------------------+

2 个答案:

答案 0 :(得分:2)

我认为你所追求的是IE的"mouseenter"事件(当用户将鼠标指针移动到对象的边界内时触发)和"mouseleave"事件(当用户将鼠标指针移到外面时触发对象的边界):

  

onmouseover事件不同,   onmouseenter事件不会冒泡。在   换句话说,onmouseenter事件   当用户移动时不会触发   鼠标指针包含的元素   由对象,而onmouseover   火了。

同样为onmouseleave

以下是一个示例:http://jsbin.com/uputi(将/edit添加到网址以编辑源代码):

<!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" xml:lang="en" lang="en"> 
<head> 
<title>Sandbox</title> 
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen"> 
#outer { width:200px; height:200px; border:1px solid #333; }
#inner { float:right; width:125px; height:80px; margin-right:-80px; border:1px solid #333; }
</style> 

<script> 
window.onload = function() {
  function mouseenter() {
    document.getElementById('dbg').innerHTML = 'mouse entered #outer boundary';
  }

  function mouseleave() {
    document.getElementById('dbg').innerHTML = 'mouse left #outer boundary';
  }

  var outer = document.getElementById('outer');

  if ('onmouseenter' in document.body) {
    // browser supports mouseenter/mouseleave natively (i.e., IE)
    outer.onmouseenter = mouseenter;
    outer.onmouseleave = mouseleave;
  }
  else {
    // simulate mouseenter/mouseleave in other browsers
    function wrap(fn) {
      return function(event) {
        var parent = event.relatedTarget;

        // Check if we're still within the same parent (traverse up parentNodes)
        while (parent && parent != this) {
          parent = parent.parentNode
        }

        if(parent != this) {
          // call the *real* mouseover/mouseout handler
          fn.call(this, event)
        }
      }
    }

    outer.onmouseover = wrap(mouseenter);
    outer.onmouseout = wrap(mouseleave);
  }
}
</script> 
</head> 
<body> 
  <div id="outer"> 
    <div><code>#outer</code></div> 
    <div>&nbsp;</div> 
    <div>&nbsp;</div> 
    <div id="inner"><code>#inner</code></div> 
  </div> 
  <div id="dbg"></div> 
</body> 
</html>

它使用relatedTarget(在标准浏览器FYI中可以正常工作),但没有状态标志。有关此处显示的仿真的详细信息,请参阅this article。 输入mouseenter元素以及 #outer元素时,您只能看到一个#inner事件被触发。这是你想要的“边界”效应(我认为)。

如果您可以选择在应用程序中包含jQuery,请{j} Query brings these fantastic events to other browsers。 (注意jQuery使用内部概述的技术,稍作修改)。

原型1.6.1 also has these events模拟。

答案 1 :(得分:0)

我认为你只需要stopPropagation