如何检查鼠标是否在jQuery中的元素上?


265

有没有一种快速简便的方法可以在我缺少的jQuery中做到这一点?

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

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

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

5
在大多数情况下,给出的答案是足够的,但是在某些情况下,mousein / out不够。例如,当鼠标不再位于菜单头或菜单主体上方时,隐藏菜单。
Marcus Downing

我使用了答案中描述的方法来处理打开动画,延迟关闭下拉菜单的图标(按钮边框的鼠标事件)。您可以使用jquery的triggerHandler方法来处理图标和下拉菜单中的延迟/取消延迟。完全足够。
mothmonsterman

#Marcus:如果隐藏菜单,哪种更好的方法呢?
coderama


如果将最佳答案标记为解决方案,我将对此表示赞成。
BBaysinger

Answers:


97

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

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

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


7
@Arthur就在这里,您还需要更多信息吗?stackoverflow.com/a/1670561/152640
mothmonsterman

270

这段代码说明了我和哈利法特(harrytime)哈里到底在说什么。当鼠标进入时,会出现一个工具提示,当鼠标离开时,它会设置一个消失的延迟。如果在延迟触发之前鼠标进入相同的元素,那么我们将使用之前存储的数据在触发器触发之前销毁它。

$("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); 
});


126

警告:is(':hover')在jQuery 1.8+中已弃用。请参阅此帖子以获取解决方案。

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

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

5
这种未记录任何地方(afik)和似乎不准确与动态示出的元件(如菜单)..
lambinator

12
自jQuery 1.9.1起已损坏!!请改用Ivo解决方案
mathheadinclouds

1
未捕获的错误:语法错误,无法识别的表达式:不支持的伪:悬停
Julio Marins 2015年

1
警告:hover不是有效jQuery选择: api.jquery.com/category/selectors(来源:bugs.jquery.com/ticket/11574

1
如果浏览器支持,它仍然可以正常工作document.querySelectorAll(':hover')
ekuusela '16

34

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

$(...).hover(
    function() { $.data(this, 'hover', true); },
    function() { $.data(this, 'hover', false); }
).data('hover', false);

if ($(something).data('hover'))
    //Hovered!

1
为什么使用data()而不添加/删除class()?一个人的表现比另一个人高吗?
psychotik 2010年

2
@psychotik:是的;$.data不涉及字符串操作。
SLaks 2010年

我在一类包裹这样的:stackoverflow.com/questions/1273566/...
ripper234

24

我确实需要一些东西(在稍微复杂的环境中,并且有很多“ 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);

然后在文档的任何地方都可以这样调用它,并返回true或false:

$("#player").ismouseover()

我在IE7 +,Chrome 1+和Firefox 4上进行了测试,并且可以正常工作。


它似乎不适用于mouseenter
wrygiel

完善。立即调用的函数表达式(IIFE),解决了使用不透明覆盖层将元素定位到对象下方的问题。辉煌!这次真是万分感谢。
亚历山大·迪克森

10

在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不兼容。
桑内,2014年

看到我的其他答案以找到IE8的解决方案
Sanne 2014年

2
@Sanne很好奇,因为$(':hover') 确实可以在IE8中使用。这是有效的CSS2伪选择器,因此应该可以使用。
towr 2014年

7

我接受了SLaks的想法,并将其包装在一小堂课中

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

6

仅供参考,以供将来的发现者使用。

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

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

正如我提到的那样,它还具有许多其他用途,如您在

jsFiddle在这里找到


5

由于无法发表评论,因此我将其作为答案!

请了解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”名称:无法附加名称为“ 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%中,还有另一种方法

希望我能帮助几个人。

格蕾兹·安迪


2

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

我花了一段时间,但我接受了您的两个建议,并提出了一些对我有用的方法。

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

$("[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,这提供了一些非常不错的鼠标悬停帮助工具提示。顺便说一句,由于复选框和文本之间的微小间隙导致移动帮助时闪烁的帮助,因此我需要延迟鼠标输出。但这就像一种魅力。对于焦点/模糊事件,我也做了类似的操作。


2

我看到超时经常用于此目的,但是在事件的背景下,您不能像这样查看坐标吗?

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事件不是由进入子元素触发的。如果您不以某种方式检查自己是否仍在父元素内,则可能会错误地采取仅当您真正离开父元素时才执行的操作。

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


2

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

$(“。pop-up”)。mouseover(function(e)
    {
    $(this).addClass(“ over”);
    });

$(“。pop-up”)。mouseout(function(e)
    {
    $(this).removeClass(“ over”);
    });


$(“#mainContent”)。mouseover(function(e){
            如果(!$(“。expanded”)。hasClass(“ over”)){
            Drupal.dhtmlMenu.toggleMenu($(“。expanded”));;
        }
    });


2

这将是最简单的方法!

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

2

这是一种不依赖jquery并使用本机DOM matches API的技术。它使用供应商前缀来支持可追溯到IE9的浏览器。有关完整详细信息,请参见caniuse.com上的matchsselector

首先创建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');

1

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

使用jQuery检测IF悬停在元素上(在撰写本文时已获得99票赞成)

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

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

仅当oijQuery对象包含单个元素时,此方法才有效。如果有多个匹配的元素,则需要将其应用于每个元素,例如:

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开始对此进行了测试。


1

这是一个可以帮助您检查鼠标是否在元素内的功能。您唯一要做的就是调用该函数,在该函数中可以有一个与鼠标实时关联的EventObject。像这样的东西:

$("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;
    }
}

0

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


0

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


1
这就是我正在考虑做的事情。将$ .data()用作SLaks似乎是完成此操作的好方法。
JamesBrownIsDead 2010年

0

我结合了该主题的思想并提出了这一点,这对于显示/隐藏子菜单很有用:

$("#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中正常工作。


0

我无法使用以上任何建议。
为什么我更喜欢我的解决方案?
此方法在您选择的任何时间检查鼠标是否在元素上。
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");
    }
});

0

只是关于上面流行且有用的Arthur Goldsmith答案的注释:如果将鼠标从IE中的一个元素移动到另一个元素(至少直到IE 9),如果新元素具有透明背景(默认情况下)。我的解决方法是为新元素提供透明的背景图像。



-1

您可以is(':visible');在jquery 中使用对于$('。item:hover'),它也可以在Jquery中使用。

这是一个htm代码snnipet:

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

});

这就是我在说的:)


1
我看不到与所提问题的关系。
安德鲁·巴伯

当您从鼠标悬停中走出来并显示隐藏的元素时,可以使用此功能;经过延迟后,您可以检查当鼠标进入要隐藏/显示的目标元素时,它是否可见
ucefkh 2013年

1
我认为您根本无法很好地理解这个问题。这根本不是他所需要的。
安德鲁·巴伯

1
什么,你正在做的是不涉及这一问题。(显然(
Andrew Barber
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.