2013-06-01 14 views
8

Tytuł pytania wyraża to, co moim zdaniem jest ostatecznym pytaniem stojącym za moim konkretnym przypadkiem.wymuś DOM przerysowanie z javascript na żądanie

Mój przypadek: Wewnątrz obsługi kliknięcia chcę, aby obraz był widoczny (animacja "ładująca") tuż przed uruchomieniem funkcji zajętości. Następnie chcę uczynić ją niewidoczną ponownie po zakończeniu funkcji. Zamiast tego, czego się spodziewałem, zdaję sobie sprawę, że obraz nigdy nie staje się widoczny. Przypuszczam, że dzieje się tak ze względu na to, że przeglądarka czeka na zakończenie programu obsługi, zanim będzie mogła przerysować (jestem pewien, że istnieją ku temu powody dobrej wydajności).

kod (również w tym skrzypce: 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'); 
    }); 
}); 

Dodałem połączenia alert zaraz po funkcja sleepStupidly aby pokazać, że w tym momencie odpoczynku przeglądarka przerysowuje, ale nie wcześniej. Niewinnie spodziewałem się, że przerysuje się zaraz po ustawieniu "wyświetlacza" na "blok";

Do rekordu próbowałem też dołączać tagi html lub wymieniać klasy css zamiast obrazu pokazującego i ukrywającego się w tym kodzie. Ten sam wynik.

Po tych wszystkich badaniach uważam, że potrzebna mi jest możliwość zmiany przeglądarki i zatrzymania wszystkich innych rzeczy do tego czasu.

Czy to możliwe? Czy jest to możliwe w trybie crossbrowser? Jakiś plugin, którego nie mogłem znaleźć ...?

Pomyślałem, że może coś takiego jak "jquery css callback" (jak w tym pytaniu: In JQuery, Is it possible to get callback function after setting new css rule?) mogłoby załatwić sprawę ... ale to nie istnieje.

Próbowałem również separte wyświetlania, wywoływania funkcji i ukrywania się w różnych programach obsługi dla tego samego zdarzenia ... ale nic. Dodanie również setTimeout w celu opóźnienia wykonania funkcji (zalecane tutaj: Force DOM refresh in JavaScript).

Dzięki i mam nadzieję, że pomoże to również innym.

Javier

EDIT (po ustawieniu mój preferowany odpowiedź):

Żeby dodatkowo wyjaśnić, dlaczego wybrano strategię window.setTimeout. W moim prawdziwym przypadku zdałem sobie sprawę, że aby dać przeglądarce czas wystarczający do przerysowania strony, musiałem dać jej około 1000 milisekund (o wiele więcej niż 50 dla przykładu skrzypiec). Uważam, że jest to spowodowane głębszym drzewem DOM (w rzeczywistości niepotrzebnie głębokim). Pozwala na to metoda setTimeout let.

+1

Czy funkcja 'window.setTimeout()' nie pomogła? –

+0

Nie należy wymagać dłuższego opóźnienia. To, czego potrzebujesz, to po prostu wstępnie załadować obraz, aby móc go natychmiast pokazać. –

+0

Rozumiem. Ale rozumiem, że tak by było, gdyby obraz nie był załadowany od początku przez przeglądarkę (co byłoby rozsądne, ponieważ jest to "display: none", jak sądzę). Tak nie jest, przynajmniej w przypadku Chrome, który wczytuje obraz od samego początku (zobacz za pomocą narzędzi programistycznych). Nadal uważam, że jest to spowodowane starszym znaczeniem, nad którym pracuję (wiele wbudowanych tabel, naprawdę ... nie zależy ode mnie!). W rzeczywistości firefox robi to lepiej (potrzebuje "mniej czasu") ... czy ma to sens? dzięki jeszcze raz. pozdrowienia – javigzz

Odpowiedz

5

Zastosowanie window.setTimeout() z jakimś krótkim niezauważalne opóźnienie uruchomienia powolny funkcję:

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

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

Live demo

7

Użyj wywołań zwrotnych JQuery show i hide (lub w inny sposób, aby wyświetlić coś takiego jak 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

Dziękuję za odpowiedź, która działa również w przypadku, który zasugerowałem. Dlatego też cię przegłosowałem (nadzieja nie jest sprzeczna z zasadami!). Wybrałem odpowiedź Marata, ponieważ lepiej mi pasuje do mojego "prawdziwego przypadku", który jest nieco bardziej skomplikowany. Dlatego uważam, że jest bardziej ogólny. pozdrowienia – javigzz

0

Nie wiem, czy to działa w Twoim przypadku (jak mam nie testowałem tego), ale podczas manipulowania CSS przy użyciu JavaScript/jQuery czasami trzeba wymusić przerysowanie określonego elementu, aby zmiany wchodzą w życie.

Dokonuje się tego, żądając po prostu właściwości CSS.

W twoim przypadku chciałbym spróbować wstawić kitty.position().left; przed wywołaniem funkcji, zanim zacznę mieszać z setTimeout.

1

Aby wymusić przerysowanie, można użyć metody offsetHeight lub getComputedStyle().

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

lub

var bar = el.offsetHeight; 

"el" jest elementem DOM

0

Co pracował dla mnie jest ustawienie następujące:

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

po tym można robić, co chcesz , i ostatecznie chcesz zrobić:

$(element).css('display','block'); 
Powiązane problemy