2010-09-10 7 views
10

In una libreria che sto utilizzando, ho il compito di spostare un elemento nella parte anteriore della dom quando viene spostato sopra. (Lo ingrandisco, quindi ho bisogno di vederlo, quindi rimpicciolirlo quando tocchi).Spostare l'elemento attivo perde l'evento di mouseout in Internet Explorer

La libreria che sto utilizzando ha una soluzione pulita che utilizza appendChildren sull'elemento attivo per spostarlo alla fine del suo padre in modo più verso la fine del dom e, a sua volta in alto.

Il problema è che, poiché l'elemento che si sta spostando è quello che si sta passando sopra l'evento mouseout, viene perso. Il tuo mouse è ancora sul nodo ma l'evento mouseout non viene sparato.

Ho spogliato la funzionalità per confermare il problema. Funziona bene in Firefox ma non in qualsiasi versione di IE. Sto usando jquery qui per la velocità. Le soluzioni possono essere in chiaro javascript vecchio ... che sarebbe una preferenza in quanto potrebbe essere necessario tornare al flusso.

Non riesco a utilizzare z-index qui poiché gli elementi sono vml, la libreria è Raphael e sto utilizzando la chiamata toFront. Esempio utilizzando ul/li per mostrare problema in un semplice esempio

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html> 
<head> 
<script src="js/jquery.min.js" type="text/javascript"></script> 
<style> 
    li 
    { 
     border:1px solid black; 
    } 
</style> 
</head> 
<body> 
<ul><li>Test 1</li></ul> 
<ul><li>Test 2</li></ul> 
<ul><li>Test 3</li></ul> 
<ul><li>Test 4</li></ul> 
<script> 
$(function(){ 
    $("li").mouseover(function(){ 
     $(this).css("border-color","red"); 
     this.parentNode.appendChild(this); 
    }); 

    $("li").mouseout(function(){ 
     $(this).css("border-color","black"); 
    }); 
}); 
</script> 
</body> 
</html> 

Edit: Ecco un link ad un bidone pasta js per vederlo in azione. http://jsbin.com/obesa4

** Modifica 2: ** Vedi tutti i commenti su tutte le risposte prima di postare molte più informazioni in questo.

+0

Non riesco a dare un senso al tuo post. vuoi che l'evento 'mouseout' si attivi mentre il tuo mouse è ancora sopra l'elemento? qual è la tua domanda attuale? – lincolnk

+0

E per this.parentNode.appendChild (this); stai cercando di aggiungere nuovamente l'elemento LI esistente? Perché non aggiungere semplicemente una classe CSS anziché aggiungere/rimuovere lo stesso elemento con il nuovo CSS? O il tuo codice originale prevede l'aggiunta di un elemento completamente nuovo da qualche altra parte all'interno dell'UL per imitare il tuo effetto "espanso" di dimensioni che hai menzionato all'inizio? – Gary

+0

Linkol Sto cercando di far funzionare il codice di esempio, ad esempio come fa in firefox. L'evento mouseout non si attiva. Sto usando gli elementi li come esempio. Come ho detto nel mio post, gli elementi sono in realtà elementi VML. Quindi cose come z-index o l'aggiunta di classi non funzioneranno, a meno che le persone non si dimostrino diverse. – johnwards

risposta

12

Il problema è che IE gestisce mouseover in modo diverso, perché si comporta come mouseenter e mousemove combinati su un elemento. Negli altri browser è solo mouseenter.

Quindi, anche dopo che il mouse è entrato nell'elemento di destinazione e hai cambiato il suo aspetto e lo ha riapplicato al suo genitore mouseover continuerà a sparare per ogni movimento del mouse, l'elemento verrà nuovamente riattivato, impedendo ad altri gestori di eventi di essere chiamato.

La soluzione è emulare il corretto comportamento mouseover modo che le azioni di onmouseover vengono eseguite una sola volta.

$("li").mouseover(function() { 
    // make sure these actions are executed only once 
    if (this.style.borderColor != "red") { 
     this.style.borderColor = "red"; 
     this.parentNode.appendChild(this); 
    } 
}); 

Esempi

  1. Extented demo of yours
  2. Example dimostrando la differenza mouseover tra i browser (bonus: javascript nativo)
+0

Brillante, esattamente quello che speravo quando ho impostato la taglia. Il mio codice si sta comportando molto meglio ora, non ho nemmeno bisogno di hackerare questo. – johnwards

+0

I'm gald I could help :) – galambalazs

+3

Ecco un semplice esempio in Raphael 2.0.2 http://jsfiddle.net/K2bSY/2/ per persone che hanno riscontrato lo stesso problema usando toFront(), mostrando una correzione di esempio usando Raphael. funzione data() – user568458

0

Questo è strabiliante e sembra essere solo IE (ma lo è anche VML). Se l'elemento genitore ha un'altezza specificata, puoi collegare il gestore del mouseout al genitore ... ma sembra che non funzioni nella tua situazione. La migliore alternativa è usare il mouseover sugli elementi adiacenti per nasconderlo:

$(function() 
{ 
    $("li").mouseover(function() 
    { 
     $("li").css("border-color", "black"); 
     $(this).css("border-color", "red"); 
     this.parentNode.appendChild(this); 
    }); 
}); 

o SVG. Puoi usare z-index in SVG.

+0

Hmm l'alternativa è penso che la soluzione qui. Fondamentalmente dovrò chiamare una funzione di reset su tutti gli altri elementi del mouseover che genereranno l'animazione di restringimento. È molto goffo ma potrebbe funzionare. Vorrò votare questa risposta per ora, e vedere se qualcun altro può pensare a qualcosa. – johnwards

1

sono stato in grado di farlo funzionare con div annidati e un evento MouseEnter sul genitore:

<div id="frame"> 
    <div class='box'></div> 
    <div class='box'></div> 
    <div class='box'></div> 
    <div class='box'></div> 
</div> 
... 
$('#frame').mouseenter(function() { 
    $(".box").css("border-color", "black"); 
}); 

Ecco una versione di lavoro utilizzando Raphael:

http://jsfiddle.net/xDREx/

+0

Si può far funzionare tutto. Non succede niente quando topo sopra le scatole. – johnwards

+0

Hai provato il collegamento? Quale browser utilizzate? L'ho fatto funzionare in IE6, IE7 e IE8. – webXL

+0

Ooh mouseenter sul genitore, questo è fondamentalmente quello che stai facendo. Che accende il reset. Bello. Tuttavia non risolve il problema principale degli eventi che vanno persi. (Clicca anche per l'evento!) Deffo vale comunque la metà dei 200 punti. Se potessi ottenere l'elemento per arrivare in cima senza perdere eventi sarei un uomo felice. (JSFiddle dev'essere stato down, funzionante alla grande ora) – johnwards

0

ho modificato risposta @galambalazs' perché ho scoperto che fallito se mi sono librato molto velocemente sugli elementi li, come alcuni degli elementi manterrebbe comunque l'effetto mouseover.

Mi è venuta una soluzione che rimuove lo stato di passaggio del mouse sugli elementi che non hanno attivato l'evento mouseover spingendo questi elementi in uno stack ogni volta che viene attivato anche lo mouseover. Ogni volta che l'evento sia mouseover o mouseout è chiamato, ho pop gli elementi di questo array e rimuovere gli stili poste su di essa:

$(function(){ 

    // Track any hovered elements 
    window.hovered = []; 

    $("li").mouseover(function() { 
     // make sure that these actions happen only once 
     if ($(this).css("border-color") != "red") { 
      resetHovered(); // Reset any previous hovered elements 
      $(this).css("border-color","red"); 
      this.parentNode.appendChild(this); 
      hovered.push(this); 
     } 
    }); 

    $("li").mouseout(function(){ 
     resetHovered(); // Reset any previous hovered elements 
    }); 

    // Reset any elements on the stack 
    function resetHovered() { 
     while (hovered.length > 0) { 
      var elem = hovered.pop(); 
      $(elem).css("border-color","black"); 
     } 
    } 
}); 

Ho provato questa soluzione con IE 11. Un esempio di funzionalità possono essere trovati here.