【问题标题】:How do I check if the mouse is over an element in jQuery?如何检查鼠标是否在jQuery中的元素上?
【发布时间】:2010-11-19 09:39:54
【问题描述】:

在我缺少的 jQuery 中是否有一种快速简便的方法来执行此操作?

我不想使用 mouseover 事件,因为我已经将它用于其他事情。我只需要知道鼠标在给定时刻是否在某个元素上。

我想做这样的事情,只要有一个“IsMouseOver”功能:

function hideTip(oi) {
    setTimeout(function() { if (!IsMouseOver(oi)) $(oi).fadeOut(); }, 100);
}

【问题讨论】:

  • 对于大多数目的,给出的答案就足够了,但在某些情况下鼠标输入/输出是不够的。例如,当鼠标不再位于菜单头或菜单主体上时隐藏菜单。
  • 我已经使用我的答案中描述的方法来处理打开动画、延迟关闭下拉菜单的图标(按钮边框的鼠标事件)。您可以使用 jquery 的 triggerHandler 方法处理图标和下拉菜单中的延迟/取消延迟。完全够用。
  • #Marcus:如果隐藏菜单,有什么更好的方法?
  • 如果最佳答案被标记为解决方案,我会投票赞成。

标签: jquery mouseover


【解决方案1】:

这段代码说明了happytime harry 和我想说的内容。当鼠标进入时,会出现一个工具提示,当鼠标离开时,它会设置一个延迟以使其消失。如果鼠标在触发延迟之前进入了相同的元素,那么我们使用我们之前存储的数据在触发之前销毁触发器。

$("someelement").mouseenter(function(){
    clearTimeout($(this).data('timeoutId'));
    $(this).find(".tooltip").fadeIn("slow");
}).mouseleave(function(){
    var someElement = $(this),
        timeoutId = setTimeout(function(){
            someElement.find(".tooltip").fadeOut("slow");
        }, 650);
    //set the timeoutId, allowing us to clear this trigger if the mouse comes back over
    someElement.data('timeoutId', timeoutId); 
});

【讨论】:

    【解决方案2】:

    干净优雅的悬停检查:

    if ($('#element:hover').length != 0) {
        // do something ;)
    }
    

    【讨论】:

    【解决方案3】:

    警告:is(':hover') 在 jquery 1.8+ 中已弃用。请参阅this post 以获得解决方案。

    您也可以使用这个答案:https://stackoverflow.com/a/6035278/8843 来测试鼠标是否悬停在一个元素上:

    $('#test').click(function() {
        if ($('#hello').is(':hover')) {
            alert('hello');
        }
    });
    

    【讨论】:

    • 这在任何地方都没有记录(afik),并且对于动态显示的元素(如菜单)似乎并不准确..
    • 从 jQuery 1.9.1 开始被破坏!!改用 Ivo 的解决方案
    • 未捕获的错误:语法错误,无法识别的表达式:不支持的伪:悬停
    • 警告:hover 不是有效的 jQuery 选择器:api.jquery.com/category/selectors(来源:bugs.jquery.com/ticket/11574
    • 浏览器支持document.querySelectorAll(':hover')还是可以的
    【解决方案4】:

    在 mouseout 上设置超时以淡出并将返回值存储到对象中的数据中。然后onmouseover,如果数据中有值则取消超时。

    删除淡出回调的​​数据。

    使用 mouseenter/mouseleave 实际上更便宜,因为当子鼠标悬停/mouseout 触发时,它们不会触发菜单。

    【讨论】:

    【解决方案5】:

    您可以使用 jQuery 的hover 事件手动跟踪:

    $(...).hover(
        function() { $.data(this, 'hover', true); },
        function() { $.data(this, 'hover', false); }
    ).data('hover', false);
    
    if ($(something).data('hover'))
        //Hovered!
    

    【讨论】:

    • 为什么使用 data() 而不是 add/removeclass()?一个比另一个性能更好吗?
    • @psychotik:是的; $.data 不涉及字符串操作。
    • 我把它封装在一个类中:stackoverflow.com/questions/1273566/…
    【解决方案6】:

    我需要一些完全一样的东西(在稍微复杂一点的环境中,并且有很多“mouseenters”和“mouseleaves”的解决方案不能正常工作)所以我创建了一个小 jquery 插件来添加方法 ismouseover。到目前为止,它运行良好。

    //jQuery ismouseover  method
    (function($){ 
        $.mlp = {x:0,y:0}; // Mouse Last Position
        function documentHandler(){
            var $current = this === document ? $(this) : $(this).contents();
            $current.mousemove(function(e){jQuery.mlp = {x:e.pageX,y:e.pageY}});
            $current.find("iframe").load(documentHandler);
        }
        $(documentHandler);
        $.fn.ismouseover = function(overThis) {  
            var result = false;
            this.eq(0).each(function() {  
                    var $current = $(this).is("iframe") ? $(this).contents().find("body") : $(this);
                    var offset = $current.offset();             
                    result =    offset.left<=$.mlp.x && offset.left + $current.outerWidth() > $.mlp.x &&
                                offset.top<=$.mlp.y && offset.top + $current.outerHeight() > $.mlp.y;
            });  
            return result;
        };  
    })(jQuery);
    

    然后在文档的任何地方你都这样称呼它,它返回真或假:

    $("#player").ismouseover()
    

    我在 IE7+、Chrome 1+ 和 Firefox 4 上测试过,运行正常。

    【讨论】:

    • 它似乎不适用于 mouseenter (Chrome) - codepen.io/anon/pen/kcypB
    • 完美。立即调用的函数表达式 (IIFE),它解决了使用不透明覆盖来定位元素下方的对象的问题。杰出的!谢谢你。
    【解决方案7】:

    在 jQuery 中你可以使用 .is(':hover'),所以

    function IsMouseOver(oi)
    {
       return $(oi).is(':hover');
    }
    

    现在将是提供 OP 中请求的功能的最简洁方式。

    注意:以上不适用于IE8或更低版本

    作为在 IE8 中工作的不太简洁的替代方案(如果我可以信任 IE9 的 IE8 模式),并且这样做不需要到处触发$(...).hover(...),也不需要知道元素的选择器(在这种情况下,Ivo 的答案是更容易):

    function IsMouseOver(oi)
    {
        return oi.length && 
               oi.parent()
                 .find(':hover')
                 .filter(function(s){return oi[0]==this})
                 .length > 0;
    }
    

    【讨论】:

    • 这不是有效的 jQuery 选择器!人们不得不停止建议这种方法。它无处不在,并且与 IE8 不兼容。
    • 查看我的其他答案以获得 IE8 的解决方案
    • @Sanne 这很好奇,因为$(':hover') 确实在 IE8 中工作。这是一个有效的 CSS2 伪选择器,所以它应该可以工作。
    【解决方案8】:

    我采纳了 SLaks 的想法并将其封装在 small class 中。

    function HoverWatcher(selector){
      this.hovering = false;
      var self = this; 
    
      this.isHoveringOver = function() { 
        return self.hovering; 
      } 
    
        $(selector).hover(function() { 
          self.hovering = true; 
        }, function() { 
          self.hovering = false; 
        }) 
    } 
    
    var box1Watcher = new HoverWatcher('#box1');
    var box2Watcher = new HoverWatcher('#box2');
    
    
    
    $('#container').click(function() {
      alert("box1.hover = " + box1Watcher.isHoveringOver() +
            ", box2.hover = " + box2Watcher.isHoveringOver());
    });
    

    【讨论】:

      【解决方案9】:

      仅供未来发现者参考。

      我制作了一个 jQuery 插件,它可以做到这一点以及更多。在我的插件中,要获取光标当前悬停的所有元素,只需执行以下操作:

      $.cursor("isHover"); // will return jQ object of all elements the cursor is 
                           // currently over & doesn't require timer
      

      正如我所提到的,它还有很多其他用途,您可以在

      jsFiddle found here

      中看到

      【讨论】:

        【解决方案10】:

        由于我无法发表评论,所以我会写这个作为答案!

        请理解css选择器“:hover”和悬停事件的区别!

        ":hover" 是一个 css 选择器,在像 $("#elementId").is(":hover") 这样使用时确实与事件一起被删除,但它的意思是它与 jQuery 事件悬停实际上无关。

        如果您编码$("#elementId:hover"),则仅当您用鼠标悬停时才会选择该元素。上述语句将适用于所有 jQuery 版本,因为您使用纯合法的 css 选择来选择此元素。

        另一方面,事件悬停是

        $("#elementId").hover(
             function() { 
                 doSomething(); 
             }
        ); 
        

        确实不推荐使用 jQuery 1.8 这里来自 jQuery 网站的状态:

        当使用事件名称“hover”时,事件子系统会​​对其进行转换 到事件字符串中的“mouseenter mouseleave”。这很烦人 几个原因:

        语义:悬停不等于鼠标进出 一个元素,它意味着一定程度的减速或延迟之前 射击。事件名称:附加处理程序返回的 event.type 是 不是悬停,而是 mouseenter 或 mouseleave。没有其他事件发生 这。选择“悬停”名称:无法附加 名称为“hover”的事件并使用 .trigger("hover") 触发它。这 文档已经将这个名称称为“强烈反对新代码”,我会 喜欢在 1.8 中正式弃用它并最终将其删除。

        他们为什么删除了 is(":hover") 尚不清楚,但好吧,你仍然可以像上面一样使用它,这里有一个小技巧可以继续使用它。

        (function ($) {
           /** 
            * :hover selector was removed from jQuery 1.8+ and cannot be used with .is(":hover") 
            * but using it in this way it works as :hover is css selector! 
            *
            **/
            $.fn.isMouseOver = function() {
                return $(this).parent().find($(this).selector + ":hover").length > 0;
            };
        })(jQuery);
        

        哦,我不会推荐超时版本,因为这会带来很多复杂性,如果没有其他方法,请使用超时功能来处理这类事情并相信我,在 95% 的情况下,还有另一种方法

        希望我能帮助一些人。

        问候安迪

        【讨论】:

          【解决方案11】:

          感谢你们俩。在某些时候,我不得不放弃尝试检测鼠标是否仍在元素上方。我知道这是可能的,但可能需要太多代码才能完成。

          我花了一点时间,但我接受了你的两个建议,并想出了一些对我有用的东西。

          这是一个简化的(但实用的)示例:

          $("[HoverHelp]").hover (
              function () {
                  var HelpID = "#" + $(this).attr("HoverHelp");
                  $(HelpID).css("top", $(this).position().top + 25);
                  $(HelpID).css("left", $(this).position().left);
                  $(HelpID).attr("fadeout", "false");
                  $(HelpID).fadeIn();
              },
              function () {
                  var HelpID = "#" + $(this).attr("HoverHelp");
                  $(HelpID).attr("fadeout", "true");
                  setTimeout(function() { if ($(HelpID).attr("fadeout") == "true") $(HelpID).fadeOut(); }, 100);
              }
          );
          

          然后要在某些文本上进行这项工作,这就是我所要做的:

          <div id="tip_TextHelp" style="display: none;">This help text will show up on a mouseover, and fade away 100 milliseconds after a mouseout.</div>
          
          This is a <span class="Help" HoverHelp="tip_TextHelp">mouse over</span> effect.
          

          除了许多精美的 CSS 之外,它还提供了一些非常漂亮的鼠标悬停帮助工具提示。顺便说一句,我需要延迟鼠标移出,因为复选框和文本之间的微小间隙导致当您移动鼠标时帮助闪烁。但这就像一个魅力。我也为焦点/模糊事件做了类似的事情。

          【讨论】:

            【解决方案12】:

            我看到很多用于此的超时,但在事件的上下文中,你不能像这样查看坐标吗?:

            function areXYInside(e){  
                    var w=e.target.offsetWidth;
                    var h=e.target.offsetHeight;
                    var x=e.offsetX;
                    var y=e.offsetY;
                    return !(x<0 || x>=w || y<0 || y>=h);
            }
            

            根据上下文,您可能需要在调用 areXYInside(e) 之前确定 (this==e.target)。

            fyi- 我正在研究在 dragLeave 处理程序中使用这种方法,以确认 dragLeave 事件不是通过进入子元素触发的。如果您不以某种方式检查您是否仍在父元素中,您可能会错误地采取仅适用于您真正离开父元素的操作。

            编辑:这是一个好主意,但不能始终如一地工作。也许有一些小的调整。

            【讨论】:

              【解决方案13】:

              您可以使用jQuery 测试任何子 div 是否具有特定的类。然后,当您将鼠标悬停在某个 div 上并移出某个 div 时,通过应用该类,您可以测试您的鼠标是否在该 div 上,即使您将鼠标悬停在页面上的不同元素上也可以这样使用更少的代码。我之所以使用它是因为我在弹出窗口中的 div 之间有空格,并且我只想在离开弹出窗口时关闭弹出窗口,而不是当我将鼠标移到弹出窗口中的空格上时。所以我在内容 div 上调用了一个 mouseover 函数(弹出窗口结束了),但它只会在我将鼠标悬停在内容 div 上时触发关闭函数,并且在弹出窗口之外!

              $(".pop-up").mouseover(函数(e) { $(this).addClass("over"); }); $(".pop-up").mouseout(函数(e) { $(this).removeClass("over"); }); $("#mainContent").mouseover(function(e){ if (!$(".expanded").hasClass("over")) { Drupal.dhtmlMenu.toggleMenu($(".expanded")); } });

              【讨论】:

                【解决方案14】:

                这将是最简单的方法!

                  function(oi) 
                  {
                   if(!$(oi).is(':hover')){$(oi).fadeOut(100);}
                  }
                

                【讨论】:

                  【解决方案15】:

                  这是一种不依赖 jquery 并使用原生 DOM matches API 的技术。它使用供应商前缀来支持可追溯到 IE9 的浏览器。详情请参阅matchesselector on caniuse.com

                  首先创建matchesSelector函数,如下:

                  var matchesSelector = (function(ElementPrototype) {
                  var fn = ElementPrototype.matches ||
                            ElementPrototype.webkitMatchesSelector ||
                            ElementPrototype.mozMatchesSelector ||
                            ElementPrototype.msMatchesSelector;
                  
                  return function(element, selector) {
                    return fn.call(element, selector);
                  };
                  
                  })(Element.prototype);
                  

                  然后,检测悬停:

                  var mouseIsOver = matchesSelector(element, ':hover');
                  

                  【讨论】:

                    【解决方案16】:

                    我已经在另一个问题中回答了这个问题,并提供了您可能需要的所有详细信息:

                    Detect IF hovering over element with jQuery(在撰写本文时已获得 99 票)

                    基本上,您可以执行以下操作:

                    var ishovered = oi.is(":hover");
                    

                    这仅在oi 是一个包含单个元素的 jQuery 对象时才有效。如果匹配的元素有多个,则需要对每个元素都应用,例如:

                    var hoveredItem = !!$('ol>li').filter(function() { return $(this).is(":hover"); });
                                      // not .filter(':hover'), as we can't apply :hover on multiple elements
                    

                    这是从 jQuery 1.7 开始测试的。

                    【讨论】:

                      【解决方案17】:

                      这是一个帮助您检查鼠标是否在元素内的函数。您唯一应该做的就是调用函数,您可以在其中拥有一个与鼠标相关的活动对象。像这样:

                      $("body").mousemove(function(event){
                           element_mouse_is_inside($("#mycontainer", event, true, {});
                      });
                      

                      您可以在github或帖子底部查看源代码:

                      https://github.com/mostafatalebi/ElementsLocator/blob/master/elements_locator.jquery.js

                      function element_mouse_is_inside  (elementToBeChecked, mouseEvent, with_margin, offset_object)
                      {
                          if(!with_margin)
                          {
                              with_margin = false;
                          }
                          if(typeof offset_object !== 'object')
                          {
                              offset_object = {};
                          }
                          var elm_offset = elementToBeChecked.offset();
                          var element_width = elementToBeChecked.width();
                          element_width += parseInt(elementToBeChecked.css("padding-left").replace("px", ""));
                          element_width += parseInt(elementToBeChecked.css("padding-right").replace("px", ""));
                          var element_height = elementToBeChecked.height();
                          element_height += parseInt(elementToBeChecked.css("padding-top").replace("px", ""));
                          element_height += parseInt(elementToBeChecked.css("padding-bottom").replace("px", ""));
                          if( with_margin)
                          {
                              element_width += parseInt(elementToBeChecked.css("margin-left").replace("px", ""));
                              element_width += parseInt(elementToBeChecked.css("margin-right").replace("px", ""));
                              element_height += parseInt(elementToBeChecked.css("margin-top").replace("px", ""));
                              element_height += parseInt(elementToBeChecked.css("margin-bottom").replace("px", ""));
                          }
                      
                          elm_offset.rightBorder = elm_offset.left+element_width;
                          elm_offset.bottomBorder = elm_offset.top+element_height;
                      
                          if(offset_object.hasOwnProperty("top"))
                          {
                              elm_offset.top += parseInt(offset_object.top);
                          }
                          if(offset_object.hasOwnProperty("left"))
                          {
                              elm_offset.left += parseInt(offset_object.left);
                          }
                          if(offset_object.hasOwnProperty("bottom"))
                          {
                              elm_offset.bottomBorder += parseInt(offset_object.bottom);
                          }
                          if(offset_object.hasOwnProperty("right"))
                          {
                              elm_offset.rightBorder += parseInt(offset_object.right);
                          }
                          var mouseX = mouseEvent.pageX;
                          var mouseY = mouseEvent.pageY;
                      
                          if(  (mouseX > elm_offset.left && mouseX < elm_offset.rightBorder)
                              && (mouseY > elm_offset.top && mouseY < elm_offset.bottomBorder) )
                          {
                              return true;
                          }
                          else
                          {
                              return false;
                          }
                      }
                      

                      【讨论】:

                        【解决方案18】:

                        扩展“Happytime harry”所说的内容,请务必使用 .data() jquery 函数来存储超时 ID。这样一来,当稍后在同一元素上触发“mouseenter”时,您可以非常轻松地检索超时 id,从而消除触发工具提示消失的触发器。

                        【讨论】:

                          【解决方案19】:

                          您可以使用 jQuery 的 mouseenter 和 mouseleave 事件。您可以在鼠标进入所需区域时设置标志,并在鼠标离开该区域时取消设置标志。

                          【讨论】:

                          • 这就是我想做的事情。 SLaks 建议使用 $.data() 似乎是实现这一目标的好方法。
                          【解决方案20】:

                          我结合了这个主题的想法并想出了这个,这对于显示/隐藏子菜单很有用:

                          $("#menu_item_a").mouseenter(function(){
                             clearTimeout($(this).data('timeoutId'));
                             $("#submenu_a").fadeIn("fast");
                          }).mouseleave(function(){
                             var menu_item = $(this);
                          
                             var timeoutId = setTimeout(function(){
                                if($('#submenu_a').is(':hover'))
                                {
                                  clearTimeout(menu_item.data('timeoutId'));
                                }
                                else
                                {
                                  $("#submenu_a").fadeOut("fast");
                                }
                             }, 650);
                          
                              menu_item.data('timeoutId', timeoutId); 
                          });
                          
                           $("#submenu_a").mouseleave(function(){
                             $(this).fadeOut("fast");
                           });
                          

                          似乎对我有用。希望这对某人有所帮助。

                          编辑:现在意识到这种方法在 IE 中无法正常工作。

                          【讨论】:

                            【解决方案21】:

                            我无法使用上述任何建议。
                            为什么我更喜欢我的解决方案?
                            此方法在您选择的任何时间检查鼠标是否在元素上。
                            Mouseenter:hover 很酷,但是 mouseenter 会触发仅当您移动鼠标时,而不是当元素在鼠标下方移动时。
                            :hover 很可爱但是... IE

                            所以我这样做:

                            否 1. 每次移动鼠标时存储鼠标 x、y 位置,
                            否 2. 检查鼠标是否在任何元素上匹配查询做一些事情……比如触发 mouseenter 事件

                            // define mouse x, y variables so they are traced all the time
                            var mx = 0; //  mouse X position
                            var my = 0; //  mouse Y position
                            
                            // update mouse x, y coordinates every time user moves the mouse
                            $(document).mousemove(function(e){
                                mx = e.pageX;
                                my = e.pageY;
                            });
                            
                            // check is mouse is over an element at any time You need (wrap it in function if You need to)
                            $("#my_element").each(function(){
                                boxX = $(this).offset().left;
                                boxY = $(this).offset().top;
                                boxW = $(this).innerWidth();
                                boxH = $(this).innerHeight();
                                if ((boxX <= mx) &&
                                    (boxX + 1000 >= mx) &&
                                    (boxY <= my) &&
                                    (boxY + boxH >= my))
                                {
                                    // mouse is over it so you can for example trigger a mouseenter event
                                    $(this).trigger("mouseenter");
                                }
                            });
                            

                            【讨论】:

                              【解决方案22】:

                              请注意上面流行且有用的 Arthur Goldsmith 回答:如果您在 IE 中将鼠标从一个元素移动到另一个元素(至少在 IE 9 之前),如果新的元素具有透明背景(默认情况下)。我的解决方法是给新元素一个透明的背景图片。

                              【讨论】:

                                【解决方案23】:
                                $(document).hover(function(e) {
                                    alert(e.type === 'mouseenter' ? 'enter' : 'leave');
                                });
                                

                                FIDDLE

                                【讨论】:

                                  【解决方案24】:

                                  你可以在 jquery 中使用is(':visible'); 对于 $('.item:hover') 它也在 Jquery 中工作。

                                  这是一个htm代码片段:

                                      <li class="item-109 deeper parent">
                                  <a class="root" href="/Comsopolis/index.php/matiers"><span>Matiers</span></a>
                                  <ul>
                                  <li class="item-110 noAff">
                                  <a class=" item sousMenu" href="/Comsopolis/index.php/matiers/tsdi">
                                  <span>Tsdi</span>
                                  </a>
                                  </li>
                                  <li class="item-111 noAff">
                                  <a class="item" href="/Comsopolis/index.php/matiers/reseaux">
                                  <span>Réseaux</span>
                                  </a>
                                  </li>
                                  </ul>
                                  </li>
                                  

                                  这是 JS 代码:

                                  $('.menutop > li').hover(function() {//,.menutop li ul
                                  
                                      $(this).find('ul').show('fast');
                                  
                                  },function() {
                                      if($(this).find('ul').is(':hover'))
                                      $(this).hide('fast');
                                  
                                  });
                                  
                                   $('.root + ul').mouseleave(function() {
                                      if($(this).is(':visible'))
                                      $(this).hide('fast');
                                  
                                  });
                                  

                                  这就是我所说的:)

                                  【讨论】:

                                  • 我看不出这与所提出的问题有什么关系。
                                  • 我认为您根本没有很好地阅读这个问题。这根本不是他需要的。
                                  • 在做什么与this question无关。 (显然(
                                  猜你喜欢
                                  • 1970-01-01
                                  • 2014-09-20
                                  • 1970-01-01
                                  • 2017-09-24
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 2014-01-25
                                  • 2016-07-22
                                  相关资源
                                  最近更新 更多