Come disabilitare gli eventi del mouseout attivati ​​da elementi figlio?


107

Lasciatemi descrivere il problema in dettaglio:

Voglio mostrare un div posizionato assoluto quando si passa con il mouse su un elemento. È davvero semplice con jQuery e funziona perfettamente. Ma quando il mouse passa su uno degli elementi figlio, attiva l'evento mouseout del div contenitore. Come faccio a impedire a JavaScript di attivare l'evento mouseout dell'elemento contenitore quando si passa con il mouse su un elemento figlio.

Qual è il modo migliore e più breve per farlo con jQuery?

Ecco un esempio semplificato per illustrare cosa intendo:

html:

<a>Hover Me</a>
<div>
  <input>Test</input>
  <select>
    <option>Option 1</option>
    <option>Option 2</option>
  </select>
</div>

JavaScript / jQuery:

$('a').hover( function() { $(this).next().show() }
              function() { $(this).next().hide() } );

Risposte:


209

La domanda è un po 'vecchia, ma mi sono imbattuto in questo l'altro giorno.

Il modo più semplice per farlo con le versioni recenti di jQuery è usare gli eventi mouseentere mouseleaveinvece di mouseovere mouseout.

Puoi testare rapidamente il comportamento con:

$(".myClass").on( {
   'mouseenter':function() { console.log("enter"); },
   'mouseleave':function() { console.log("leave"); }
});

4
Ha aiutato il mio problema relativo a javascript non jquery. Stavo usando mouseenter / mouseout invece di mouseleave con i miei ascoltatori di eventi!
Jo E.

1
Per motivi di ricerca, questi comportamenti degli eventi del mouse sono equivalenti a ROLL_OVERe ROLL_OUTin AS3.
Jeff Ward

2
Mi ha risparmiato qualche mal di testa. È strano come il passaggio del mouse sugli elementi figlio inneschi l' mouseoutevento genitore , quando in realtà è ancora all'interno dell'elemento genitore.
javiniar.leonard

18

Per semplicità, riorganizzerei un po 'l'html per inserire il contenuto appena visualizzato all'interno dell'elemento a cui è associato l'evento mouseover:

<div id="hoverable">
  <a>Hover Me</a>
  <div style="display:none;">
    <input>Test</input>
    <select>
      <option>Option 1</option>
      <option>Option 2</option>
    </select>
  </div>
</div>

Quindi, potresti fare qualcosa del genere:

$('#hoverable').hover( function() { $(this).find("div").show(); },
                       function() { $(this).find("div").hide(); } );

Nota: non consiglio il CSS inline, ma è stato fatto per rendere l'esempio più facile da digerire.


Questa è davvero una soluzione molto semplice e pulita. Grazie per avermi ricordato. Ma nella mia situazione specifica, che non è esattamente come nella domanda, questa non è un'opzione. Grazie comunque!
Sander Versluys

Dopo aver provato diversi metodi come descritto da altri qui a SO, sono tornato al tuo metodo e l'ho fatto funzionare nel mio caso. Sìì! :-)
Sander Versluys

11

Sì, ragazzi, usate .mouseleaveinvece di .mouseout:

$('div.sort-selector').mouseleave(function() {
    $(this).hide();
});

O anche usarlo in combinazione con live:

$('div.sort-selector').live('mouseleave', function() {
    $(this).hide();
});

8

Stai cercando l'equivalente jQuery del bubbling di eventi di javascript.

Controllalo:

http://docs.jquery.com/Events/jQuery.Event#event.stopPropagation.28.29

Fondamentalmente è necessario catturare l'evento nei nodi DOM figli e interrompere la loro propagazione sull'albero DOM. Un altro modo, sebbene in realtà non suggerito (in quanto può seriamente compromettere gli eventi esistenti sulla tua pagina), è impostare l'acquisizione degli eventi su un elemento specifico nella pagina e riceverà tutti gli eventi. Questo è utile per il comportamento DnD e simili, ma sicuramente non per il tuo caso.


funziona come dovrebbe, non so perché non sei riuscito a farlo funzionare .. solo un'informazione
zappan

3

Sto semplicemente controllando se le coordinate del mouse sono esterne all'elemento nell'evento mouseout.

Funziona ma è un sacco di codice per una cosa così semplice :(

function mouseOut(e)
{
    var pos = GetMousePositionInElement(e, element);
    if (pos.x < 0 || pos.x >= element.size.X || pos.y < 0 || pos.y >= element.size.Y)
    {
        RealMouseOut();
    }
    else
    {
         //Hit a child-element
    }
}

Il codice ridotto per la leggibilità, non funzionerà immediatamente.


1

Sono d'accordo con Ryan.

Il tuo problema è che il div "successivo" non è un "figlio" di A. Non c'è modo per HTML o jQuery di sapere che il tuo elemento "a" è correlato al div figlio nel DOM. Avvolgerli e mettere un passaggio del mouse sull'involucro significa che sono associati.

Tieni presente che il suo codice non è in linea con le migliori pratiche, però. Non impostare lo stile nascosto in linea sugli elementi; se l'utente ha CSS ma non javascript, l'elemento verrà nascosto e non potrà essere mostrato. La pratica migliore è inserire quella dichiarazione nell'evento document.ready.


Sono totalmente d'accordo con l'inserimento di hide nell'evento document.ready. Il CSS inline era solo per trasmettere un esempio funzionante nel modo più semplice possibile. Modificherò la mia risposta per renderlo chiaro.
Ryan McGeary

1

Ho risolto questo problema aggiungendo i pointer-events: none;miei elementi figlio css


Ciò ha davvero aiutato molto quando si correggeva un codice legacy che costruiva i propri popover con eventi di mouseover e mouseleave
CM

0

Il modo in cui di solito ho visto questo gestito è di avere un ritardo di circa 1/2 secondo tra lo spostamento del mouse dall'elemento HoverMe. Quando si sposta il mouse nell'elemento al passaggio del mouse, si desidera impostare una variabile che segnali che si sta passando il mouse sull'elemento e quindi sostanzialmente interrompere la parte al passaggio del mouse dal nascondersi se questa variabile è impostata. È quindi necessario aggiungere una funzione Nascondi simile su OnMouseOut dall'elemento al passaggio del mouse per farlo scomparire quando si rimuove il mouse. Mi dispiace di non poterti dare alcun codice o qualcosa di più concreto, ma spero che questo ti indichi nella giusta direzione.


Sì idd, ho appena implementato una soluzione del genere. È un problema molto comune. Sono davvero curioso di sapere quali altre soluzioni ci sono ... Grazie per la risposta!
Sander Versluys

0

È una vecchia domanda, ma non diventa mai obsoleta. La risposta corretta dovrebbe essere quella data dalla bytebrite .

Vorrei solo sottolineare la differenza tra mouseover / mouseout e mouseenter / mouseleave. Puoi leggere una spiegazione utile e utile qui (vai in fondo alla pagina per una demo funzionante). Quando lo usi mouseout, l'evento si interrompe quando il mouse entra in un altro elemento, anche se è un elemento figlio. D'altra parte, quando si utilizza mouseleave, l'evento non viene attivato quando il mouse passa sopra un elemento figlio, e questo è il comportamento che l'OP vorrebbe ottenere.

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.