代码之家  ›  专栏  ›  技术社区  ›  meandmycode

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

  •  1
  • meandmycode  · 技术社区  · 15 年前

    假设我有以下元素:

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

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

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

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

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

    这是按设计的,而且设计非常好,但是-如果我想在鼠标悬停在我身上时做一个动作(包括我的孩子项目),我需要做一些额外的工作来阻止我不感兴趣的事件。例如,这将起作用:

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

    基本上,代码有一个状态变量来确定鼠标是否“过多”父级(通过其子级或不通过子级),以及当“过多”时是否再次触发事件,这些事件将被忽略。我们还捕获鼠标悬停事件并询问它。相关目标(你要进入的目标)是我吗?(父母),还是我的最后一个孩子?如果是这样,那就不要做任何事……否则,将“overed”状态设置为false。

    所以代码实际上可以工作,但是假设我不能使用RelatedTarget属性来确定下一个目标,那么您将如何进行这种行为呢?

    我希望这是有道理的,我觉得在没有相关目标的情况下,事件中没有足够的上下文来完成它,但我觉得可能存在一个角度来改变EventPhase属性的行为(以确定事件是直接的还是冒泡的)。

    另外,我也不想寻找答案说“这在Ie,Yadda-Yadda行不通”。我现在只在使用W3C事件规范浏览器。

    事先谢谢, 史蒂芬。


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

    +------------------+
    |                  |
    |                  +--+
    |                     |
    |                     |
    |                  +--+
    |                  |
    +------------------+
    
    2 回复  |  直到 15 年前
        1
  •  2
  •   Crescent Fresh    15 年前

    我想你想要的是 "mouseenter" 事件(当用户在对象边界内移动鼠标指针时激发)和 "mouseleave" 事件(当用户将鼠标指针移到对象边界之外时激发):

    不像 onmouseover 事件 onmouseenter 事件不冒泡。在 换句话说, 鼠标器 事件 当用户移动 鼠标指针指向包含的元素 根据对象,而 鼠标开关 着火了。

    同上 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 正如您所做的(在标准浏览器FYI中工作正常),但没有状态标志。见 this article 有关此处显示的仿真的更多详细信息。 你只能看到一个 mouseenter 事件在进入时被激发 #outer 元素, 以及 这个 #inner 元素。这就是你要追求的“边界”效应(我想)。

    如果您可以选择在应用程序中包含jquery,j Query brings these fantastic events to other browsers . (注意jquery使用了内部概述的技术,并做了一些小的修改)。

    1.1.1原型 also has these events 模拟。

        2
  •  0
  •   Josh Stodola    15 年前

    我想你只需要 stopPropagation