web-dev-qa-db-fra.com

Comment vérifier si la souris survole un élément dans jQuery?

Existe-t-il un moyen rapide et facile de faire cela dans jQuery qui me manque?

Je ne veux pas utiliser l'événement mouseover, car je l'utilise déjà pour autre chose. J'ai juste besoin de savoir si la souris survole un élément à un moment donné.

Je voudrais faire quelque chose comme ceci, si seulement il y avait une fonction "IsMouseOver":

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

Définissez un délai d'expiration de la souris pour la fermeture en fondu et stockez la valeur de retour dans les données de l'objet. Ensuite, annulez le délai d'attente s'il y a une valeur dans les données.

Supprimez les données sur le rappel du fondu.

Il est en fait moins coûteux d’utiliser mouseenter/mouseleave car ils ne se déclenchent pas pour le menu lorsque les enfants mouseover/mouseout sont activés.

96
happytime harry

Ce code illustre ce que happytime harry et moi essayons de dire. Lorsque la souris entre, une info-bulle apparaît, lorsque la souris quitte, elle fixe un délai pour sa disparition. Si la souris entre dans le même élément avant que le délai ne soit déclenché, nous détruisons le déclencheur avant qu'il ne s'éteigne en utilisant les données que nous avons stockées auparavant.

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

Un contrôle en vol stationnaire propre et élégant:

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

AVERTISSEMENT: is(':hover') est obsolète dans jQuery 1.8+. Voir ce post pour une solution.

Vous pouvez également utiliser cette réponse: https://stackoverflow.com/a/6035278/884 pour vérifier si la souris survole un élément:

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

Vous pouvez utiliser l'événement hover de jQuery pour garder une trace manuellement:

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

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

J'avais besoin de quelque chose exactement comme ça (dans un environnement un peu plus complexe et la solution avec beaucoup de 'mouseenters' et 'mouseleaves' ne fonctionnait pas correctement), j'ai donc créé un petit plugin jquery qui ajoute la méthode ismouseover. Cela a plutôt bien fonctionné jusqu'à présent.

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

Puis, n'importe où dans le document, appelez-le comme ceci et renvoie true ou false:

$("#player").ismouseover()

Je l'ai testé sur IE7 +, Chrome 1+ et Firefox 4, et fonctionne correctement.

24
Ivan Castellanos

Dans jQuery, vous pouvez utiliser .is (': hover'), donc

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

serait maintenant le moyen le plus concis de fournir la fonction demandée dans le PO.

Remarque: ce qui précède ne fonctionne pas dans IE8 ou inférieur

Comme alternative moins succincte qui fonctionne dans IE8 (si je peux faire confiance au modus IE8 d'IE9), et cela sans déclencher $(...).hover(...) partout, ni nécessitant de connaître un sélecteur pour l'élément (auquel cas la réponse d'Ivo est plus facile ):

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

J'ai pris l'idée de SLaks et l'ai emballée dans un petite classe .

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

JUST FYI pour les futurs chercheurs de cela.

J'ai créé un plugin jQuery capable de faire cela et bien plus encore. Dans mon plugin, pour obtenir tous les éléments sur lesquels le curseur est actuellement survolé, procédez comme suit:

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

Comme je l'ai mentionné, il a également beaucoup d'autres utilisations que vous pouvez voir dans le

jsFiddle trouvé ici

6
SpYk3HH

Comme je ne peux pas commenter, je vais écrire ceci comme une réponse!

S'il vous plaît comprendre la différence entre css selector ": hover" et l'événement hover!

": hover" est un sélecteur css et a bien été supprimé de l’événement lorsqu’il est utilisé comme ceci $("#elementId").is(":hover"), mais sa signification n’a vraiment rien à voir avec le survol de jQuery.

si vous codez $("#elementId:hover"), l'élément ne sera sélectionné que lorsque vous passez la souris sur celle-ci. La déclaration ci-dessus fonctionnera avec toutes les versions de jQuery en sélectionnant cet élément avec une sélection css pure et légitime.

D'autre part, l'événement survole qui est

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

est en effet déprécié comme jQuery 1.8 ici l'état du site web jQuery:

Lorsque le nom d'événement "survol" est utilisé, le sous-système d'événement le convertit en "mouseenter mouseleave" dans la chaîne d'événement. Ceci est agaçant pour plusieurs raisons:

Sémantique: le survol n'est pas la même chose que l'entrée et la sortie d'un élément de la souris, cela implique une certaine décélération ou un certain délai avant le déclenchement. Nom de l'événement: Le type d'événement renvoyé par le gestionnaire attaché n'est pas un survol, mais soit mouseenter ou mouseleave. Aucun autre événement ne fait cela. Cooptation du nom "hover": Il n'est pas possible d'associer un événement avec le nom "hover" et de le déclencher à l'aide de .trigger ("hover"). Les docs appellent déjà ce nom "fortement déconseillé pour le nouveau code", je voudrais le déconseiller officiellement pour la version 1.8 et le supprimer éventuellement.

Pourquoi ils ont supprimé l'utilisation est (": hover") n'est pas clair, mais bon, vous pouvez toujours l'utiliser comme ci-dessus et voici un petit hack pour l'utiliser quand même.

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

Oh et moi je ne le recommanderais pas la version de délai d'attente comme ceci apporte beaucoup de complexité, utilisez les fonctionnalités de délai d'attente pour ce genre de choses s'il n'y a pas d'autre moyen et croyez-moi, en 95% des cas, il existe un autre moyen!

J'espère pouvoir aider quelques personnes là-bas.

Greetz Andy

4
Phenix

Voici une technique qui ne repose pas sur jquery et utilise le DOM natif matchesAPI . Il utilise les préfixes du fournisseur pour prendre en charge les navigateurs revenant à IE9. Voir matchesselector sur caniuse.com pour tous les détails.

Commencez par créer la fonction matchesSelector, comme suit:

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

Ensuite, pour détecter le vol stationnaire:

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

Je vois beaucoup de délais utilisés pour cela, mais dans le contexte d'un événement, ne pouvez-vous pas regarder les coordonnées, comme ceci ?:

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

Selon le contexte, vous devrez peut-être vérifier (this == e.target) avant d'appeler areXYInside (e).

fyi- je cherche à utiliser cette approche dans un gestionnaire dragLeave, afin de confirmer que l'événement dragLeave n'a pas été déclenché en entrant dans un élément enfant. Si, d'une manière ou d'une autre, vous ne vérifiez pas que vous êtes toujours à l'intérieur de l'élément parent, vous risquez, par erreur, de prendre des mesures destinées uniquement au moment où vous quittez réellement le parent.

EDIT: c'est une bonne idée, mais ne fonctionne pas assez régulièrement. Peut-être avec quelques petites modifications.

2
dlo

Vous pouvez tester avec jQuery si un div enfant a une certaine classe. Ensuite, en appliquant cette classe lorsque vous passez la souris sur un certain div, vous pouvez tester si votre souris le survole, même lorsque vous survolez un élément différent de la page. Beaucoup moins de code de cette façon. J'ai utilisé cela parce que j'avais des espaces entre les divs dans une fenêtre contextuelle, et je voulais uniquement fermer la fenêtre contextuelle lorsque je m'éloignais de la fenêtre contextuelle, et non lorsque je passais la souris sur les espaces de la fenêtre contextuelle. J'ai donc appelé une fonction mouseover sur la div de contenu (la fenêtre contextuelle était terminée), mais cela ne déclencherait la fonction de fermeture que lorsque la souris se serait déplacée sur la div de contenu, et que cette dernière était en dehors de la fenêtre contextuelle!

 
 $ (". pop-up"). mouseover (fonction (e) 
 {
 $ (this) .addClass ("over"); 
}); 
 
 $ (". pop-up"). mouseout (fonction (e) 
 {
 $ (this) .removeClass ("over"); 
}); 
 
 
 $ ("# mainContent"). mouseover (fonction (e) {
 si (! $ (". Expanded"). hasClass ("over")) {
 Drupal.dhtmlMenu.toggleMenu ($ (". Expand")); 
} 
} ); 
 
2
Nate

Merci à vous deux. À un moment donné, j'ai dû cesser d'essayer de détecter si la souris était toujours au-dessus de l'élément. Je sais que c'est possible, mais peut nécessiter trop de code à accomplir.

Cela m'a pris un peu de temps, mais j’ai pris vos deux suggestions et proposé quelque chose qui pourrait fonctionner pour moi.

Voici un exemple simplifié (mais fonctionnel):

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

Et puis pour faire ce travail sur un texte c'est tout ce que j'ai à faire:

<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.

Avec beaucoup de CSS sophistiqués, cela permet quelques très bonnes infobulles d’aide au passage de la souris. A propos, j’avais besoin de retard dans la souris en raison de minuscules espaces entre les cases à cocher et le texte qui faisait clignoter l’aide lorsque vous déplacez la souris. Mais cela fonctionne comme un charme. J'ai également fait quelque chose de similaire pour les événements de focus/flou.

2
Steve Wortham

Ce serait le moyen le plus simple de le faire!

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

J'ai répondu à cela dans une autre question, avec tous les détails dont vous pourriez avoir besoin:

Detect IF survole un élément avec jQuery (a 99 votes positifs au moment de l'écriture)

En gros, vous pouvez faire quelque chose comme:

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

Cela ne fonctionne que si oi est un objet jQuery contenant un seul élément. Si plusieurs éléments correspondent, vous devez appliquer à chaque élément, par exemple:

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

Cela a été testé à partir de jQuery 1.7.

1
Meligy

J'ai combiné les idées de ce sujet et proposé ce qui est utile pour afficher/masquer un sous-menu:

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

Semble travailler pour moi. J'espère que ça aide quelqu'un.

EDIT: Réalisant maintenant que cette approche ne fonctionne pas correctement dans IE.

0
Two Piers

En prolongeant ce que dit 'Happytime harry', veillez à utiliser la fonction jquery .data () pour stocker l'identifiant du délai d'expiration. Cela vous permet de récupérer très facilement l'identifiant du délai d'expiration lorsque le "mouseenter" est déclenché ultérieurement sur le même élément, ce qui vous permet d'éliminer le déclencheur de la disparition de votre info-bulle.

0
Arthur Goldsmith

Je ne pouvais utiliser aucune des suggestions ci-dessus.
Pourquoi je préfère ma solution?
Cette méthode vérifie si la souris survole un élément à à tout moment que vous choisissez.
Mouseenter et : survolez sont cool, mais mouseenter ne se déclenche que si vous déplacez la souris, et non pas lorsque l'élément se déplace sous la souris.
: le vol stationnaire est assez doux mais ... IE

Alors je fais ça:

No 1. mémoriser la position x, y de la souris chaque fois que vous la déplacez lorsque vous en avez besoin,
No 2. vérifier si la souris survole l'un des éléments correspondant à la requête do stuff ... comme déclencher un événement 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
Hyper Motion

Juste une remarque sur la réponse populaire et utile d’Arthur Goldsmith ci-dessus: Si vous déplacez votre souris d’un élément à un autre dans IE (au moins jusqu’à IE 9), difficulté à obtenir le bon fonctionnement de ce dernier si le nouvel élément a un arrière-plan transparent (ce qui serait le cas par défaut). Ma solution a consisté à donner au nouvel élément une image d’arrière-plan transparente.

0
Jish

Vous pouvez utiliser les événements mouseenter et mouseleave de jQuery. Vous pouvez définir un drapeau lorsque la souris entre dans la zone souhaitée et le désactiver lorsqu'il quitte la zone.

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

VIOLON

0
yckart

Voici une fonction qui vous aide à vérifier si la souris est ou non dans un élément. La seule chose à faire est d’appeler la fonction dans laquelle vous pouvez avoir un événement en direct associé à la souris. quelque chose comme ça:

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

Vous pouvez voir le code source ici dans github ou au bas de l'article:

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
Mostafa Talebi