Come posso verificare se il mouse si trova su un elemento in jQuery?


265

C'è un modo semplice e veloce per farlo in jQuery che mi manca?

Non voglio usare l'evento mouseover perché lo sto già usando per qualcos'altro. Devo solo sapere se il mouse si trova su un elemento in un determinato momento.

Mi piacerebbe fare qualcosa del genere, se solo ci fosse una funzione "IsMouseOver":

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

5
Per la maggior parte degli scopi le risposte fornite sono sufficienti, ma ci sono casi in cui il mousein / out non è sufficiente. Ad esempio, nascondere un menu quando il mouse non si trova più sulla testa del menu O sul corpo del menu.
Marcus Downing,

Ho usato il metodo descritto nella mia risposta per lavorare con icone (eventi del mouse per i bordi dei pulsanti) che aprono menu a discesa di chiusura animati e ritardati. Gestisci il ritardo / annulla ritardo sia nell'icona che nel menu a discesa utilizzando i metodi triggerHandler di jquery. Completamente sufficiente.
mothmonsterman,

#Marcus: se si nasconde un menu, qual è il modo migliore per farlo?
coderama,


Lo avrei votato se la risposta migliore fosse stata contrassegnata come soluzione.
BBaysinger,

Risposte:


97

Impostare un timeout al passaggio del mouse per dissolvenza e memorizzare il valore restituito nei dati nell'oggetto. Quindi onmouseover, annulla il timeout se è presente un valore nei dati.

Rimuovere i dati al momento della richiamata della dissolvenza.

In realtà è meno costoso utilizzare mouseenter / mouseleave perché non si attivano per il menu quando i bambini passano il mouse / mouseout.


7
@Arthur ha fatto proprio qui, hai ancora bisogno di maggiori informazioni? stackoverflow.com/a/1670561/152640
mothmonsterman

270

Questo codice illustra ciò che happytime harry e io stiamo cercando di dire. Quando il mouse entra, viene emessa una descrizione comandi, quando il mouse esce lascia un ritardo affinché scompaia. Se il mouse entra nello stesso elemento prima dell'attivazione del ritardo, allora distruggiamo il trigger prima che si disattivi utilizzando i dati precedentemente memorizzati.

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

ATTENZIONE: is(':hover')è obsoleto in jquery 1.8+. Vedi questo post per una soluzione.

È inoltre possibile utilizzare questa risposta: https://stackoverflow.com/a/6035278/8843 per verificare se il mouse passa con il mouse su un elemento:

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

5
Questo non è documentato da nessuna parte (afik) e non sembra essere accurato con elementi mostrati dinamicamente (come un menu) ..
lambinator

12
rotto a partire da jQuery 1.9.1 !! usa invece la soluzione di Ivo
mathheadinclouds

1
Errore non rilevato: errore di sintassi, espressione non riconosciuta: pseudo non supportato: hover
Julio Marins

1
Attenzione : :hovernon è un selettore jQuery valido: api.jquery.com/category/selectors (fonte: bugs.jquery.com/ticket/11574 )
Pang

1
Funziona ancora se il browser supportadocument.querySelectorAll(':hover')
ekuusela il

34

È possibile utilizzare l' hoverevento di jQuery per tenere traccia manualmente:

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

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

1
perché usare data () e non aggiungere / removeclass ()? Uno è più performante dell'altro?
psychotik

2
@psychotik: Sì; $.datanon comporta la manipolazione di stringhe.
SLaks,

Ho avvolto questo in una classe: stackoverflow.com/questions/1273566/...
ripper234

24

Avevo bisogno di qualcosa esattamente come questo (in un ambiente un po 'più complesso e la soluzione con molti "mouseenter" e "mouseleaves" non funzionava correttamente), quindi ho creato un piccolo plugin jquery che aggiunge il metodo ismouseover. Finora ha funzionato abbastanza bene.

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

Quindi in qualsiasi punto del documento lo chiami in questo modo e restituisce vero o falso:

$("#player").ismouseover()

L'ho provato su IE7 +, Chrome 1+ e Firefox 4 e funziona correttamente.


Non sembra funzionare su mouseenter (Chrome) - codepen.io/anon/pen/kcypB
wrygiel

Perfetto. Espressione della funzione immediatamente invocata (IIFE) che risolve il problema del targeting di oggetti sotto l'elemento con sovrapposizione di opacità. Brillante! Grazie per questo.
Alexander Dixon,

10

In jQuery puoi usare .is (': hover'), quindi

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

sarebbe ora il modo più conciso per fornire la funzione richiesta nel PO.

Nota: quanto sopra non funziona in IE8 o versioni precedenti

Come alternativa meno succinta che funziona in IE8 (se posso fidarmi del modus IE8 di IE9), e lo fa senza innescare ovunque $(...).hover(...), né richiede di conoscere un selettore per l'elemento (nel qual caso la risposta di Ivo è più semplice):

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

Questo non è un selettore jQuery valido! Le persone devono smettere di suggerire questo metodo. È ovunque e non compatibile con IE8.
Sanne,

Vedi la mia altra risposta per avere una soluzione per IE8
Sanne,

2
@Sanne E 'curioso, perché $(':hover') fa il lavoro in IE8. È uno pseudo-selettore CSS2 valido, quindi dovrebbe funzionare.
tra il

7

Ho preso l'idea di SLaks e l'ho avvolta in una piccola 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());
});

6

SOLO FYI per i futuri cercatori di questo.

Ho creato un plug-in jQuery che può fare questo e molto altro. Nel mio plugin, per ottenere tutti gli elementi su cui è attualmente posizionato il cursore, è sufficiente fare quanto segue:

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

Come ho già detto, ha anche molti altri usi come puoi vedere nel

jsFiddle trovato qui


5

Poiché non posso commentare, quindi scriverò questo come una risposta!

Comprendi la differenza tra il selettore CSS ": hover" e l'evento hover!

": hover" è un selettore css ed è stato effettivamente rimosso con l'evento quando utilizzato in questo modo $("#elementId").is(":hover") , ma nel suo significato non ha davvero nulla a che fare con l'hover degli eventi jQuery.

se codifichi $("#elementId:hover") , l'elemento verrà selezionato solo quando si passa con il mouse. l'istruzione sopra funzionerà con tutte le versioni di jQuery mentre selezioni questo elemento con selezione css pura e legittima.

D'altra parte, il passaggio del mouse sull'evento che è

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

è infatti deprecato come jQuery 1.8 qui lo stato dal sito Web jQuery:

Quando viene utilizzato il nome dell'evento "hover", il sottosistema evento lo converte in "mouseenter mouseleave" nella stringa dell'evento. Questo è fastidioso per diversi motivi:

Semantica: il passaggio del mouse non è lo stesso del mouse che entra e esce da un elemento, implica una certa quantità di decelerazione o ritardo prima di sparare. Nome evento: il tipo di evento restituito dal gestore collegato non è al passaggio del mouse, ma mouseenter o mouseleave. Nessun altro evento fa questo. Cooptazione del nome "hover": non è possibile associare un evento con il nome "hover" e attivarlo utilizzando .trigger ("hover"). I documenti già chiamano questo nome "fortemente scoraggiato per il nuovo codice", vorrei deprecarlo ufficialmente per 1.8 e alla fine rimuoverlo.

Perché hanno rimosso l'utilizzo è (": hover") non è chiaro ma vabbè, puoi ancora usarlo come sopra e qui c'è un piccolo trucco per usarlo ancora.

(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, e non consiglierei la versione di timeout in quanto ciò porta molta complessità , utilizzare le funzionalità di timeout per questo tipo di cose se non c'è altro modo e credetemi, nel 95% per cento di tutti i casi c'è un altro modo !

Spero di poter aiutare un paio di persone là fuori.

Salve Andy


2

Grazie a tutti e due. Ad un certo punto ho dovuto rinunciare a provare a rilevare se il mouse era ancora sopra l'elemento. So che è possibile, ma potrebbe richiedere troppo codice per realizzare.

Mi ci è voluto un po 'di tempo, ma ho preso entrambi i tuoi suggerimenti e ho trovato qualcosa che avrebbe funzionato per me.

Ecco un esempio semplificato (ma funzionale):

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

E poi, per far funzionare questo testo, è tutto ciò che devo fare:

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

Insieme a un sacco di fantasiosi CSS, questo consente alcuni suggerimenti di aiuto per il passaggio del mouse molto belli. A proposito, ho avuto bisogno del ritardo nel passaggio del mouse a causa di piccoli spazi tra le caselle di controllo e il testo che causavano il lampeggiamento dell'aiuto mentre si spostava il mouse. Ma questo funziona come un fascino. Ho anche fatto qualcosa di simile per gli eventi focus / blur.


2

Vedo molto i timeout utilizzati per questo, ma nel contesto di un evento, non riesci a guardare le coordinate, in questo modo ?:

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

A seconda del contesto, potrebbe essere necessario accertarsi (this == e.target) prima di chiamare areXYInside (e).

fyi- Sto cercando di usare questo approccio all'interno di un gestore dragLeave, per confermare che l'evento dragLeave non è stato attivato andando in un elemento figlio. Se in qualche modo non verifichi di essere ancora all'interno dell'elemento genitore, potresti erroneamente intraprendere azioni intese solo quando lasci veramente il genitore.

EDIT: questa è una bella idea, ma non funziona abbastanza coerentemente. Forse con alcune piccole modifiche.


2

Puoi verificare jQueryse un div bambino ha una determinata classe. Quindi, applicando quella classe quando si passa il mouse sopra e fuori un determinato div, è possibile verificare se il mouse è sopra di esso, anche quando si passa il mouse su un elemento diverso nella pagina Molto meno codice in questo modo. L'ho usato perché avevo spazi tra i div in un pop-up e volevo chiudere il pop-up solo quando mi sono allontanato dal pop-up, non quando stavo spostando il mouse sugli spazi nel pop-up. Quindi ho chiamato una funzione di passaggio del mouse sul div del contenuto (su cui era saltato il pop-up), ma avrebbe attivato la funzione di chiusura solo quando ho inserito il div del contenuto, ed era al di fuori del pop-up!

$ ( "Pop-up"). Mouseover (function (e)
    {
    $ (This) .addClass ( "over");
    });

$ ( "Pop-up"). Mouseout (function (e)
    {
    $ (This) .removeClass ( "over");
    });


$ ( "# MainContent"). Mouseover (function (e) {
            if (! $ (". extended"). hasClass ("over")) {
            Drupal.dhtmlMenu.toggleMenu ($ () "espanso.");
        }
    });


2

Questo sarebbe il modo più semplice per farlo!

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

2

Ecco una tecnica che non si basa su jquery e utilizza l' matches API DOM nativa . Utilizza i prefissi del fornitore per supportare i browser risalenti a IE9. Vedi il matchesselector su caniuse.com per tutti i dettagli.

Per prima cosa crea la funzione matchSelector, in questo modo:

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

Quindi, per rilevare il passaggio del mouse:

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

1

Ho risposto a questa domanda in un'altra domanda, con tutti i dettagli di cui potresti aver bisogno:

Rileva IF al passaggio del mouse sopra l'elemento con jQuery (al momento della scrittura ha 99 voti positivi)

Fondamentalmente, puoi fare qualcosa del tipo:

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

Funziona solo se oiè un oggetto jQuery che contiene un singolo elemento. Se sono presenti più elementi corrispondenti, è necessario applicare a ciascun elemento, ad esempio:

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

Questo è stato testato a partire da jQuery 1.7.


1

Ecco una funzione che ti aiuta a verificare se il mouse si trova all'interno di un elemento o meno. L'unica cosa che dovresti fare è chiamare la funzione in cui puoi avere un EventObject live associato al mouse. qualcosa come questo:

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

Puoi vedere il codice sorgente qui in github o nella parte inferiore del post:

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

Estendendo quanto detto da "Happytime harry", assicurati di utilizzare la funzione jquery .data () per memorizzare l'ID timeout. Ciò consente di recuperare facilmente l'id di timeout quando il "mouseenter" viene attivato sullo stesso elemento in un secondo momento, consentendo di eliminare il trigger per la scomparsa della descrizione comandi.


0

È possibile utilizzare gli eventi mouseenter e mouseleave di jQuery. È possibile impostare una bandiera quando il mouse entra nell'area desiderata e disinserire la bandiera quando lascia l'area.


1
Questo è quello che stavo pensando di fare. Usare $ .data () come suggerisce SLaks sembra essere un buon modo per farlo.
JamesBrownÈ morto

0

Ho unito le idee di questo argomento e ne sono uscito, utile per mostrare / nascondere un sottomenu:

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

Sembra funzionare per me. Spero che questo aiuti qualcuno.

EDIT: ora rendersi conto che questo approccio non funziona correttamente in IE.


0

Non ho potuto usare nessuno dei suggerimenti sopra.
Perché preferisco la mia soluzione?
Questo metodo controlla se il mouse si trova su un elemento in qualsiasi momento scelto da te .
Mouseenter e : hover sono fantastici, ma mouseenter si innesca solo se sposti il ​​mouse, non quando l'elemento si sposta sotto il mouse.
: hover è piuttosto dolce ma ... IE

Quindi faccio questo:

No 1. memorizza la posizione del mouse x, y ogni volta che viene spostato quando necessario,
No 2. controlla se il mouse si trova su uno qualsiasi degli elementi che corrispondono alla query eseguono operazioni ... come attivare un evento 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

Solo una nota sulla popolare e utile risposta di Arthur Goldsmith sopra: Se stai spostando il mouse da un elemento all'altro in IE (almeno fino a IE 9), potresti avere qualche problema a farlo funzionare correttamente se il nuovo elemento ha un sfondo trasparente (che sarebbe di default). La mia soluzione è stata quella di dare al nuovo elemento un'immagine di sfondo trasparente.


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

VIOLINO


-1

Puoi usare is(':visible');in jquery e per $ ('. Item: hover') funziona anche in jquery.

questo è uno snnipet di codice 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>

e questo è il codice 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');

});

questo è quello di cui stavo parlando :)


1
Non vedo come sia correlato alla domanda posta.
Andrew Barber,

puoi usarlo quando esci dal passaggio del mouse e visualizzi il tuo elemento nascosto e dopo un ritardo puoi verificare se è visibile quando il mouse entra nell'elemento target che vuoi nascondere / mostrare
ucefkh

1
Non credo che tu abbia letto la domanda molto bene. Questo non è affatto ciò di cui ha bisogno.
Andrew Barber,

1
Quello che stai facendo non è legato a questa domanda . (apparentemente (
Andrew Barber,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.