是否有一个快速和简单的方法来做到这一点在jQuery,我错过了?

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

我想做一些这样的事情,如果有一个“IsMouseOver”函数:

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

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

删除淡出的回调数据。

使用mouseenter/mouseleave实际上成本更低,因为当child鼠标悬停/鼠标退出触发时,它们不会触发菜单。


谢谢你们俩。在某种程度上,我不得不放弃尝试检测鼠标是否仍然停留在元素上。我知道这是可能的,但可能需要太多的代码来实现。

我花了一点时间,但我接受了你们的建议,并想出了适合我的办法。

下面是一个简单的例子:

$("[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,这允许一些非常漂亮的鼠标悬停帮助工具提示。顺便说一下,我需要在鼠标退出时延迟,因为复选框和文本之间的微小间隙导致当你移动鼠标时帮助会闪烁。但这就像一个魔法。我也为焦点/模糊事件做了类似的事情。


You can test with jQuery if any child div has a certain class. Then by applying that class when you mouse over and out out a certain div, you can test whether your mouse is over it, even when you mouse over a different element on the page Much less code this way. I used this because I had spaces between divs in a pop-up, and I only wanted to close the pop up when I moved off of the pop up, not when I was moving my mouse over the spaces in the pop up. So I called a mouseover function on the content div (which the pop up was over), but it would only trigger the close function when I moused-over the content div, AND was outside the pop up!


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

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


$("#mainContent").mouseover(function(e){
            if (!$(".expanded").hasClass("over")) {
            Drupal.dhtmlMenu.toggleMenu($(".expanded"));
        }
    });


扩展什么'Happytime harry'说,一定要使用.data() jquery函数来存储超时id。这样,当'mouseenter'在同一个元素上被触发时,你可以很容易地检索超时id,允许你消除触发,让你的工具提示消失。


这段代码说明了我和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); 
});

你可以使用jQuery的悬停事件来手动跟踪:

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

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

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


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

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.t target)。

我正在考虑在dragLeave处理程序中使用这种方法,以确认dragLeave事件不是由进入子元素触发的。如果您没有以某种方式检查您是否仍然在父元素中,那么您可能会错误地执行仅在真正离开父元素时才执行的操作。

编辑:这是一个很好的想法,但并不能始终如一地工作。也许要做一些小调整。


我需要的东西正是这样的(在一个更复杂的环境和解决方案有很多'mouseenter '和'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上进行了测试,运行正常。


我采纳了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());
});

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

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

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

只是供未来的发现者参考。

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

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

正如我提到的,它还有很多其他用途,您可以在这里找到的jsFiddle中看到


$(document).hover(function(e) {
    alert(e.type === 'mouseenter' ? 'enter' : 'leave');
});

小提琴


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

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


一个干净优雅的悬停检查:

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

我不能使用上面的任何建议。 为什么我更喜欢我的解决方案? 此方法检查鼠标是否在您所选择的任何时间停留在元素上。 Mouseenter和:hover很酷,但是Mouseenter只在你移动鼠标时触发,而不是当元素在鼠标下移动时触发。 :盘旋很可爱,但是…即

所以我这样做:

没有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");
    }
});

你可以使用is(':visible');在jquery 对于$('.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');

});

这就是我说的:)


上面Arthur Goldsmith的回答很流行也很有用:如果你在IE中将鼠标从一个元素移动到另一个元素(至少在IE 9之前),如果新元素的背景是透明的(默认情况下是透明的),你可能会遇到一些麻烦。我的解决办法是给新元素一个透明的背景图像。


在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;
}

这将是最简单的方法!

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

我已经在另一个问题中回答了这个问题,以及你可能需要的所有细节:

使用jQuery检测IF悬停在元素上(在撰写本文时有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开始测试的。


因为我不能评论,所以我将写这作为一个答案!

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

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

如果你输入$("#elementId:hover"),元素只会在你用鼠标悬停时被选中。上面的语句将适用于所有jQuery版本,因为你选择这个元素与纯合法的css选择。

另一方面,事件悬停

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

在jQuery 1.8的时候已经被弃用了。

When the event name "hover" is used, the event subsystem converts it to "mouseenter mouseleave" in the event string. This is annoying for several reasons: Semantics: Hovering is not the same as the mouse entering and leaving an element, it implies some amount of deceleration or delay before firing. Event name: The event.type returned by the attached handler is not hover, but either mouseenter or mouseleave. No other event does this. Co-opting the "hover" name: It is not possible to attach an event with the name "hover" and fire it using .trigger("hover"). The docs already call this name "strongly discouraged for new code", I'd like to deprecate it officially for 1.8 and eventually remove it.

为什么他们删除用法是(":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%的情况下有另一种方法!

希望我能帮到一些人。

Greetz安迪


这里有一个技术,它不依赖于jquery,并使用本机DOM匹配API。它使用厂商前缀支持回到IE9的浏览器。详情请参阅caniuse.com上的matchesselector。

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

下面是一个函数,它可以帮助你检查鼠标是否在元素中。惟一需要做的是调用函数,在这里可以有一个与鼠标相关的活动eventtobject。就像这样:

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

使用 evt.originalEvent.composedPath()

MouseEvent给出了鼠标最近与之交互的HTMLElement的数组。最后一个元素是最外层的(也就是说,它总是Window)。

MouseEvent composedPath()示例如下:

通过检查该数组中是否存在可点击的元素,您将知道是否在特定元素上有鼠标悬停…

$(window).on("mouseup", onMouseUp);
const $someButton = $("a.yourButton");

function onMouseUp(evt) {
  const path = evt.originalEvent.composedPath();
  if(path.indexOf($someButton[0]) !== -1){
    // released mouse over button
  }else{
    // did not release mouse over button
  }
}

For those like me who needed an answer that didn't depend on browser mouse-over/enter/leave events or hover states. I had a situation in a home-page slider, the left and right slide click areas could overlap (or sometimes completely cover) the CTA buttons in the banner - this renders all those previous methods useless (browser only reports events on the element with the highest z-index). I was tasked with making the click event care more about the button than the banner functionality when the click is over the button.

我的完整解是这样的:

jQuery('.carousel-control-prev').on('click.testClick', function(e) {
    var bannerButtons = jQuery('.banner-content a');
    for (var i = 0; i < bannerButtons.length; i++) {
        if (isMouseOver(bannerButtons.eq(i), e)) {
            e.preventDefault();
            e.stopPropagation();
            bannerButtons[i].click();
        }
    }
});

function isMouseOver($el, e) {
    if ($el.is(':visible')) {
        var offset = $el.offset();
        var x = (e.pageX - offset.left);
        var y = (e.pageY - offset.top);
        if (x > 0 && x < $el.outerWidth() && y > 0 && y < $el.outerHeight()) {
            return true;
        }
    }
    return false;
}

这可能需要更多的工作和测试,但现在它做了我需要的-在这种情况下是拦截横幅左键点击,检查鼠标是否恰好在CTA按钮上,如果是,点击CTA而不是横幅导航。

我完全理解更好的解决方案是重新设计横幅区域,这样就不会发生这种情况,但设计超出了我的控制范围。