Evita onmouseout quando si passa il mouse sull’elemento figlio del div assoluto genitore WITHOUT jQuery

Sto avendo problemi con la funzione onmouseout in un div in posizione assoluta. Quando il mouse colpisce un elemento figlio nel div, l’evento mouseout si triggers, ma non voglio che si attivi fino a quando il mouse non esce dal genitore, div assoluto.

Come posso evitare che l’evento mouseout si mouseout quando colpisce un elemento figlio senza jquery.

So che questo ha qualcosa a che fare con l’evento che bolle, ma non ho fortuna a scoprire come farlo.

Ho trovato un post simile qui: Come disabilitare gli eventi di mouseout triggersti ​​da elementi figlio?

Tuttavia quella soluzione utilizza jQuery.

 function onMouseOut(event) { //this is the original element the event handler was assigned to var e = event.toElement || event.relatedTarget; if (e.parentNode == this || e == this) { return; } alert('MouseOut'); // handle mouse event here! } document.getElementById('parent').addEventListener('mouseout',onMouseOut,true); 

Ho fatto una rapida demo di JsFiddle, con tutti i CSS e HTML necessari, dai un’occhiata …

MODIFICA il collegamento FISSO per il supporto cross-browser http://jsfiddle.net/RH3tA/9/

NOTA che questo controlla solo il genitore immediato, se il genitore ha figli nidificati allora devi attraversare in qualche modo gli elementi che i genitori cercano “l’elemento originale”

Esempio di EDIT per bambini nidificati

EDIT Risolto per auspicabilmente cross-browser

 function makeMouseOutFn(elem){ var list = traverseChildren(elem); return function onMouseOut(event) { var e = event.toElement || event.relatedTarget; if (!!~list.indexOf(e)) { return; } alert('MouseOut'); // handle mouse event here! }; } //using closure to cache all child elements var parent = document.getElementById("parent"); parent.addEventListener('mouseout',makeMouseOutFn(parent),true); //quick and dirty DFS children traversal, function traverseChildren(elem){ var children = []; var q = []; q.push(elem); while (q.length > 0) { var elem = q.pop(); children.push(elem); pushAll(elem.children); } function pushAll(elemArray){ for(var i=0; i < elemArray.length; i++) { q.push(elemArray[i]); } } return children; } 

E un nuovo collegamento JSFiddle , EDIT aggiornato

Per una soluzione CSS semplice e semplice che funziona in alcuni casi ( IE11 o più recente ), è ansible rimuovere gli pointer-events per bambini impostandoli su none

 .parent * { pointer-events: none; } 

Usa onmouseleave .

Oppure, in jQuery, usa mouseleave()

È la cosa esatta che stai cercando. Esempio:

 

o, in jQuery:

 $(".outer").mouseleave(function(){ //your code here }); 

un esempio è qui .

Ecco una soluzione più elegante basata su ciò che è venuto sotto. rappresenta l’evento che bolle da più di un livello di bambini. Conta anche per problemi di cross-browser.

 function onMouseOut(this, event) { //this is the original element the event handler was assigned to var e = event.toElement || event.relatedTarget; //check for all children levels (checking from bottom up) while(e && e.parentNode && e.parentNode != window) { if (e.parentNode == this|| e == this) { if(e.preventDefault) e.preventDefault(); return false; } e = e.parentNode; } //Do something u need here } document.getElementById('parent').addEventListener('mouseout',onMouseOut,true); 

Se stai usando jQuery puoi anche usare la funzione “mouseleave”, che tratta tutto questo per te.

 $('#thetargetdiv').mouseenter(do_something); $('#thetargetdiv').mouseleave(do_something_else); 

do_qualcosa si attiverà quando il mouse entra in thetargetdiv o in uno dei suoi figli, do_something_else sparerà solo quando il mouse lascia il bersaglio e tutti i suoi figli.

Grazie ad Amjad Masad che mi ha ispirato.

Ho la seguente soluzione che sembra funzionare in IE9, FF e Chrome e il codice è piuttosto breve (senza la chiusura complessa e le cose trasversali del bambino):

  DIV.onmouseout=function(e){ // check and loop relatedTarget.parentNode // ignore event triggered mouse overing any child element or leaving itself var obj=e.relatedTarget; while(obj!=null){ if(obj==this){ return; } obj=obj.parentNode; } // now perform the actual action you want to do only when mouse is leaving the DIV } 

Penso che Quirksmode abbia tutte le risposte di cui hai bisogno (diversi browser che ribolliscono il comportamento e gli eventi mouseenter / mouseleave ), ma penso che la conclusione più comune di questo evento sia l’uso di un framework come JQuery o Mootools (che ha il mouseenter e eventi di mouseleave , che sono esattamente ciò che avresti intuito accadrebbe).

Dai un’occhiata a come lo fanno, se vuoi, fallo da solo
oppure puoi creare la tua versione “lean media” personalizzata di Mootools con solo la parte evento (e le sue dipendenze).

Prova mouseleave()

Esempio :

 

😉

Ho trovato una soluzione molto semplice,

basta usare l’evento onmouseleave = “myfunc ()” rispetto all’evento onmousout = “myfunc ()”

Nel mio codice ha funzionato !!

Esempio:

      
Hover mouse here
CHILD
It doesn't fires if you hover mouse over this child_div
TEXT
Show "TEXT"

Stesso esempio con la funzione mouseout:

      
Hover mouse here
CHILD
It fires if you hover mouse over this child_div
TEXT
Show "TEXT"

Spero che sia d’aiuto 🙂

Ci sono due modi per gestire questo.

1) Controlla il risultato event.target nel tuo callback per vedere se corrisponde al tuo genitore div

 var g_ParentDiv; function OnMouseOut(event) { if (event.target != g_ParentDiv) { return; } // handle mouse event here! }; window.onload = function() { g_ParentDiv = document.getElementById("parentdiv"); g_ParentDiv.onmouseout = OnMouseOut; }; 

2) O utilizzare l’acquisizione di eventi e chiamare event.stopPropagation nella funzione di callback

 var g_ParentDiv; function OnMouseOut(event) { event.stopPropagation(); // don't let the event recurse into children // handle mouse event here! }; window.onload = function() { g_ParentDiv = document.getElementById("parentdiv"); g_ParentDiv.addEventListener("mouseout", OnMouseOut, true); // pass true to enable event capturing so parent gets event callback before children }; 

Lo faccio funzionare come un fascino con questo:

 function HideLayer(theEvent){ var MyDiv=document.getElementById('MyDiv'); if(MyDiv==(!theEvent?window.event:theEvent.target)){ MyDiv.style.display='none'; } } 

Ah e il tag MyDiv è come questo:

 

In questo modo, quando onmouseout passa a un figlio, a un style.display='none' , ecc … lo style.display='none' non viene eseguito; ma quando onmouseout esce da MyDiv viene eseguito.

Quindi non c’è bisogno di fermare la propagazione, usare i timer, ecc …

Grazie per gli esempi, potrei fare questo codice da loro.

Spero che questo aiuti qualcuno.

Inoltre può essere migliorato in questo modo:

 function HideLayer(theLayer,theEvent){ if(theLayer==(!theEvent?window.event:theEvent.target)){ theLayer.style.display='none'; } } 

E poi i tag DIVs in questo modo:

 

Quindi più generale, non solo per un div e nessuna necessità di aggiungere id="..." su ogni livello.

Controllo l’offset dell’elemento originale per ottenere le coordinate della pagina dei limiti dell’elemento, quindi assicurati che l’azione di mouseout venga triggersta solo quando il mouseout non rientra in tali limiti. Sporco ma funziona.

 $(el).live('mouseout', function(event){ while(checkPosition(this, event)){ console.log("mouseovering including children") } console.log("moused out of the whole") }) var checkPosition = function(el, event){ var position = $(el).offset() var height = $(el).height() var width = $(el).width() if (event.pageY > position.top || event.pageY < (position.top + height) || event.pageX > position.left || event.pageX < (position.left + width)){ return true } } 
 var elem = $('#some-id'); elem.mouseover(function () { // Some code here }).mouseout(function (event) { var e = event.toElement || event.relatedTarget; if (elem.has(e).length > 0) return; // Some code here }); 

Se hai aggiunto (o hai) una class CSS o un id all’elemento genitore, allora puoi fare qualcosa di simile a questo:

 
JavaScript: document.getElementById("parent").onmouseout = function(e) { e = e ? e : window.event //For IE if(e.target.id == "parent") { //Do your stuff } }

Quindi roba viene eseguita solo quando l’evento è sul div padre.

Volevo solo condividere qualcosa con te.
Ho avuto un po ‘di difficoltà con gli eventi ng-mouseenter e ng-mouseleave .

Il caso di studio:

Ho creato un menu di navigazione mobile che si triggers quando il cursore si trova su un’icona.
Questo menu era in cima a ogni pagina.

  • Per gestire mostra / nascondi nel menu, seleziono una class.
    ng-class="{down: vm.isHover}"
  • Per triggersre vm.isHover , utilizzo gli eventi del mouse ng.
    ng-mouseenter="vm.isHover = true"
    ng-mouseleave="vm.isHover = false"

Per ora, tutto andava bene e funzionava come previsto.
La soluzione è semplice e pulita.

Il problema in arrivo:

In una vista specifica, ho una lista di elementi.
Ho aggiunto un pannello azioni quando il cursore si trova su un elemento dell’elenco.
Ho usato lo stesso codice di sopra per gestire il comportamento.

Il problema:

Ho capito quando il mio cursore si trova sul menu di navigazione mobile e anche sulla parte superiore di un elemento, c’è un conflitto tra loro.
Il pannello di azione si presentò e la navigazione fluttuante fu nascosta.

Il fatto è che anche se il cursore si trova sopra il menu di navigazione mobile, viene triggersto l’elemento elenco ng-mouseenter.
Non ha senso per me, perché mi aspetterei una interruzione automatica degli eventi di propagazione del mouse.
Devo dire che sono rimasto deluso e dedico un po ‘di tempo a scoprire questo problema.

Primi pensieri:

Ho provato ad usare questi:

  • $event.stopPropagation()
  • $event.stopImmediatePropagation()

Ho combinato un sacco di eventi puntatori ng (mousemove, mouveover, …) ma nessuno mi aiuta.

Soluzione CSS:

Ho trovato la soluzione con una semplice proprietà CSS che uso sempre di più:

 pointer-events: none; 

Fondamentalmente, lo uso in questo modo (sui miei elementi della lista):

 ng-style="{'pointer-events': vm.isHover ? 'none' : ''}" 

Con questo difficile, gli eventi del mouse ng non verranno più triggersti ​​e il mio menu di navigazione mobile non si chiuderà più quando il cursore si trova su di esso e su un elemento dall’elenco.

Andare oltre:

Come ci si può aspettare, questa soluzione funziona ma non mi piace.
Non controlliamo i nostri eventi ed è cattivo.
Inoltre, è necessario disporre dell’accesso vm.isHover scope di vm.isHover per ottenerlo e potrebbe non essere ansible o ansible, ma in qualche modo sporco.
Potrei fare un violino se qualcuno vuole guardare.

Tuttavia, non ho un’altra soluzione …
È una lunga storia e non posso darti una patata quindi per favore perdonami amico mio.
Ad ogni modo, pointer-events: none è vita, quindi ricordalo.

Se si ha accesso all’elemento a cui è collegato l’evento all’interno del metodo mouseout , è ansible utilizzare contains() per vedere se event.relatedTarget è un elemento figlio o meno.

Come event.relatedTarget è l’elemento a cui è passato il mouse, se non è un elemento figlio, hai eliminato il mouse dall’elemento.

 div.onmouseout = function (event) { if (!div.contains(event.relatedTarget)) { // moused out of div } } 

Sebbene la soluzione a cui si fa riferimento utilizzi jquery, mouseenter e mouseleave sono eventi dom nativi, quindi è ansible utilizzarli senza jquery.