2013-06-01 25 views
8

Tiêu đề của câu hỏi thể hiện những gì tôi nghĩ là câu hỏi cuối cùng đằng sau trường hợp cụ thể của tôi.force DOM redraw với javascript theo yêu cầu

Trường hợp của tôi: Bên trong trình xử lý nhấp, tôi muốn hiển thị hình ảnh (hoạt ảnh 'tải') ngay trước khi chức năng bận bắt đầu. Sau đó, tôi muốn làm cho nó vô hình một lần nữa sau khi chức năng đã hoàn thành. Thay vì những gì tôi mong đợi tôi nhận ra rằng hình ảnh không bao giờ trở nên hữu hình. Tôi đoán rằng điều này là do trình duyệt chờ xử lý để kết thúc, trước khi nó có thể làm bất kỳ vẽ lại (tôi chắc chắn có lý do hiệu suất tốt cho điều đó).

Mã (cũng trong fiddle này: 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'); 
    }); 
}); 

Tôi đã thêm alert cuộc gọi ngay sau khi sleepStupidly chức năng để chứng minh rằng trong khoảnh khắc đó, trình duyệt sẽ vẽ lại, nhưng không phải trước đó. Tôi ngây thơ mong đợi nó vẽ lại ngay sau khi đặt 'display' thành 'block';

Để lưu nội dung, tôi cũng đã thử thêm các thẻ html, hoặc hoán đổi các lớp css, thay vì hình ảnh hiển thị và ẩn trong mã này. Cùng một kết quả.

Sau khi nghiên cứu, tôi nghĩ rằng những gì tôi cần là khả năng để buộc trình duyệt vẽ lại và dừng mọi thứ khác cho đến lúc đó.

Có thể không? Có thể trong một cách crossbrowser? Một số plugin tôi đã không thể tìm thấy có thể ...?

Tôi nghĩ rằng có thể một cái gì đó như 'jquery css gọi lại' (như trong câu hỏi này: In JQuery, Is it possible to get callback function after setting new css rule?) sẽ làm các trick ... nhưng điều đó không tồn tại.

Tôi cũng đã cố gắng separte hiển thị, gọi hàm và ẩn trong các trình xử lý khác nhau cho cùng một sự kiện ... nhưng không có gì. Ngoài ra, hãy thêm setTimeout để trì hoãn việc thực thi hàm (như được đề xuất ở đây: Force DOM refresh in JavaScript).

Cảm ơn và tôi hy vọng nó cũng sẽ giúp người khác.

javier

EDIT (sau khi thiết câu trả lời ưa thích của tôi):

Chỉ cần tiếp tục giải thích lý do tại sao tôi chọn chiến lược window.setTimeout. Trong trường hợp sử dụng thực tế của tôi, tôi đã nhận ra rằng để cung cấp cho trình duyệt đủ thời gian để vẽ lại trang, tôi phải cung cấp cho nó khoảng 1000 mili giây (nhiều hơn 50 cho ví dụ fiddle). Điều này tôi tin là do một cây DOM sâu hơn (trên thực tế, sâu sắc không cần thiết). Phương pháp setTimeout let cho phép bạn thực hiện điều đó.

+1

Không trợ giúp 'window.setTimeout()'? –

+0

Không cần thiết để sử dụng thời gian trễ lâu hơn. Những gì bạn cần có lẽ chỉ là tải trước hình ảnh của bạn để có thể hiển thị ngay lập tức. –

+0

Tôi hiểu. Nhưng tôi hiểu rằng sẽ là trường hợp nếu hình ảnh không được tải từ đầu bởi trình duyệt (điều gì là hợp lý vì nó là 'display: none', tôi đoán). Đó không phải là trường hợp, ít nhất với chrome người tải hình ảnh từ đầu rất (nhìn thấy với các công cụ phát triển). Tôi vẫn nghĩ là do sự đánh dấu di sản mà tôi đang làm việc (rất nhiều bảng nhúng, thực sự ... không phụ thuộc vào tôi!). Trên thực tế firefox hiện nó tốt hơn (cần 'ít thời gian hơn') ... nó có ý nghĩa? cảm ơn một lần nữa. kính trọng – javigzz

Trả lời

5

Sử dụng window.setTimeout() với một số chậm trễ không đáng kể ngắn để chạy chức năng chậm:

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

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

Live demo

7

Sử dụng JQuery showhide gọi lại (hoặc cách khác để hiển thị nội dung nào đó như 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

Cảm ơn câu trả lời của bạn mà cũng làm việc cho các trường hợp tôi đã đề nghị. Đó là lý do tại sao tôi cũng upvoted bạn (hy vọng không phải là chống lại các quy tắc!). Tôi đã chọn câu trả lời của Marat bởi vì nó phù hợp với tôi tốt hơn cho 'trường hợp thực sự' của tôi phức tạp hơn một chút. Do đó tôi nghĩ là tổng quát hơn. Trân trọng – javigzz

0

Tôi không biết nếu điều này làm việc trong trường hợp của bạn (như tôi có không thử nghiệm nó), nhưng khi thao tác CSS với JavaScript/jQuery đôi khi cần thiết để buộc vẽ lại phần tử cụ thể để tạo thay đổi có hiệu lực.

Điều này được thực hiện bằng cách yêu cầu thuộc tính CSS.

Trong trường hợp của bạn, tôi sẽ thử đặt kitty.position().left; trước cuộc gọi hàm trước khi gây rối với setTimeout.

1

Để buộc vẽ lại, bạn có thể sử dụng offsetHeight hoặc getComputedStyle().

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

hoặc

var bar = el.offsetHeight; 

"el" trở thành một phần tử DOM

0

gì làm việc cho tôi là thiết lập như sau:

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

Sau đó bạn có thể làm bất cứ điều gì bạn muốn và cuối cùng bạn muốn làm:

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