2013-06-01 8 views
8

Il titolo della domanda esprime ciò che ritengo sia l'ultima domanda dietro il mio caso particolare.forzare il DOM ridisegnare con javascript su richiesta

Il mio caso: All'interno di un gestore di clic, desidero rendere visibile un'immagine (un'animazione di caricamento) subito prima dell'avvio di una funzione di occupato. Quindi voglio renderlo di nuovo invisibile dopo che la funzione è stata completata. Invece di quello che mi aspettavo, mi rendo conto che l'immagine non diventa mai visibile. Immagino che ciò sia dovuto al fatto che il browser attende che il gestore termini, prima che possa eseguire qualsiasi ridisegno (sono sicuro che ci sono buone ragioni per farlo).

Il codice (anche in questo violino: http://jsfiddle.net/JLmh4/2/)

html:

<img id="kitty" src="http://placekitten.com/50/50" style="display:none"> 
<div><a href="#" id="enlace">click to see the cat</a> </div> 

JS:

$(document).ready(function(){ 
    $('#enlace').click(function(){ 
     var kitty = $('#kitty'); 
     kitty.css('display','block'); 

     // see: http://unixpapa.com/js/sleep.html 
     function sleepStupidly(usec) 
     { 
      var endtime= new Date().getTime() + usec; 
      while (new Date().getTime() < endtime) 
       ; 
     } 

     // simulates bussy proccess, calling some function... 

     sleepStupidly(4000); 

     // when this triggers the img style do refresh! 
     // but not before 
     alert('now you do see it'); 

     kitty.css('display','none'); 
    }); 
}); 

ho aggiunto la chiamata alert subito dopo la funzione sleepStupidly per dimostrare che in quel momento di riposo, il browser si ridisegna, ma non prima. Mi aspettavo innocentemente che si ridisegnasse subito dopo aver impostato il "display" su "block";

Per la cronaca, ho anche provato ad aggiungere tag html o a scambiare classi css, invece dell'immagine che mostra e nasconde in questo codice. Stesso risultato

Dopo tutte le mie ricerche, penso che ciò di cui ho bisogno è la capacità dello di forzare il browser a ridisegnare e interrompere ogni altra cosa fino ad allora.

È possibile? È possibile in un modo crossbrowser? Qualche plugin che non sono riuscito a trovare, forse ...?

Ho pensato che forse qualcosa come "callback jquery css" (come in questa domanda: In JQuery, Is it possible to get callback function after setting new css rule?) avrebbe fatto il trucco ... ma non esiste.

Ho anche provato a separare la visualizzazione, la chiamata di funzione e nascondere in diversi gestori per lo stesso evento ... ma niente. Inoltre, aggiungere setTimeout per ritardare l'esecuzione della funzione (come consigliato qui: Force DOM refresh in JavaScript).

Grazie e spero che aiuti anche gli altri.

javier

EDIT (dopo aver impostato la mia risposta preferita):

Giusto per spiegare ulteriormente il motivo per cui ho scelto la strategia window.setTimeout. Nel mio caso d'uso reale ho capito che per dare al browser tempo sufficiente per ridisegnare la pagina, dovevo dargli circa 1000 millisecondi (molto più del 50 per l'esempio del violino). Questo credo sia dovuto ad un albero DOM più profondo (di fatto, inutilmente profondo). L'approccio setTimeout consente di farlo.

+1

Non ha funzionato 'window.setTimeout()'? –

+0

Non dovrebbe essere necessario per utilizzare un timeout più lungo. Quello di cui hai bisogno è probabilmente solo per precaricare la tua immagine per poterla mostrare immediatamente. –

+0

Vedo. Ma capisco che sarebbe il caso se l'immagine non venisse caricata dal browser (cosa sarebbe ragionevole dato che è "display: none", immagino). Questo non è il caso, almeno con Chrome che carica l'immagine fin dall'inizio (visto con gli strumenti di sviluppo). Penso ancora sia dovuto al markup legacy con cui sto lavorando (un sacco di tabelle incorporate, davvero ... non dipendenti da me!). In realtà Firefox fa meglio (ha bisogno di 'meno tempo') ... ha senso? grazie ancora. saluti – javigzz

risposta

5

Usa window.setTimeout() con qualche breve ritardo impercettibile per l'esecuzione lenta funzione:

$(document).ready(function() { 
    $('#enlace').click(function() { 
     showImage(); 

     window.setTimeout(function() { 
      sleepStupidly(4000); 
      alert('now you do see it'); 
      hideImage(); 
     }, 50); 
    }); 
}); 

Live demo

7

Utilizzare i callback JQuery show e hide (o altro modo per visualizzare qualcosa come fadeIn/fadeOut).

http://jsfiddle.net/JLmh4/3/

$(document).ready(function() { 
    $('#enlace').click(function() { 
     var kitty = $('#kitty'); 


     // see: http://unixpapa.com/js/sleep.html 
     function sleepStupidly(usec) { 
      var endtime = new Date().getTime() + usec; 
      while (new Date().getTime() < endtime); 
     } 

     kitty.show(function() { 

      // simulates bussy proccess, calling some function... 
      sleepStupidly(4000); 

      // when this triggers the img style do refresh! 
      // but not before 
      alert('now you do see it'); 

      kitty.hide(); 
     }); 
    }); 
}); 
+0

Grazie per la tua risposta, che funziona anche per il caso che ho suggerito. Ecco perché ti ho anche revocato (la speranza non è contro le regole!). Ho selezionato la risposta di Marat perché mi si addice meglio per il mio "caso reale", che è un po 'più complicato. Quindi penso che sia più generale. Saluti – javigzz

0

Non so se questo funziona nel tuo caso (come ho non testato), ma quando si manipolano i CSS con JavaScript/jQuery a volte è necessario forzare il ridisegno di un elemento specifico da rendere le modifiche hanno effetto.

Questo viene fatto semplicemente richiedendo una proprietà CSS.

Nel tuo caso, proverei a mettere un kitty.position().left; prima della chiamata di funzione prima di scherzare con setTimeout.

1

Per forzare il ridisegno, è possibile utilizzare offsetHeight o getComputedStyle().

var foo = window.getComputedStyle(el, null); 

o

var bar = el.offsetHeight; 

"el '" essere un elemento DOM

0

Quello che ha funzionato per me sta impostando la seguente:

$(element).css('display','none'); 

Dopo di che si può fare quello che vuoi , e alla fine si desidera fare:

$(element).css('display','block'); 
Problemi correlati