1

想象一下,我有以下元素:

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

内部元素的定位意味着它可以在视觉上位于其父级之外,我在父级上放置了一个事件侦听器,如下所示:

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

如果我从底部直接将鼠标悬停在父级上,我会得到一个直接事件,但是由于事件路由,如果我从侧面鼠标悬停(首先击中子级),我也会收到来自子级的事件,因为它会冒泡.

如果我一直向左走,直到我离开子元素并进入父空间,我将得到一个直接事件,如果我再次向右走,我将从子元素得到另一个冒泡事件。

这是设计使然,设计绝对没问题——如果我想在鼠标悬停在我身上(包括我的子项目)时执行 SINGLE 动作,我需要做一些额外的工作来阻止我不感兴趣的事件。 . 例如,这将起作用:

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);

本质上,代码有一个状态变量来确定鼠标是否“超过”父级(通过其子级或不通过其子级),以及事件是否在“超过”时再次触发,这些事件被忽略..我们还捕获鼠标退出事件并问它..是relatedTarget(你要进入的目标)我吗?(父母),还是我最终的孩子?如果是这样,那么不要做任何事情.. 否则将“过度”状态设置为 false。

所以该代码实际上是有效的,但想象一下我不能使用relatedTarget 属性来确定下一个目标,你将如何做这种行为?

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

此外,我不是在寻找“这在 IE 中不起作用,yadda yadda”的答案。我现在只针对 w3c 事件规范浏览器工作。


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

+------------------+
|                  |
|                  +--+
|                     |
|                     |
|                  +--+
|                  |
+------------------+
4

2 回答 2

2

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

onmouseover事件不同的是, onmouseenter事件不会冒泡。换句话说,onmouseenter当用户将鼠标指针移到对象包含的元素上时,该事件不会触发,而onmouseover 会触发。

同上onmouseleave

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

<!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和你一样使用(在标准浏览器中可以正常工作,仅供参考),但没有状态标志。有关此处显示的仿真的更多详细信息,请参阅本文。您可以看到在输入元素mouseenter时只触发了一个事件,以及元素。这是您要追求的“边界”效应(我认为)。#outer#inner

如果您可以选择在您的应用程序中包含 jQuery,jQuery会将这些奇妙的事件带到其他浏览器中。(注意 jQuery 使用了她内部概述的技术,并进行了一些小的修改)。

原型 1.6.1模拟了这些事件。

于 2009-11-04T16:34:46.750 回答
0

我认为你只需要stopPropagation

于 2009-11-04T15:40:03.600 回答