Javascript - Cách phát hiện nếu tài liệu đã được tải (IE 7 / Firefox 3)


163

Tôi muốn gọi một chức năng sau khi tải tài liệu, nhưng tài liệu có thể hoặc chưa tải xong. Nếu nó đã tải, thì tôi chỉ có thể gọi hàm. Nếu nó KHÔNG tải, thì tôi có thể đính kèm một trình nghe sự kiện. Tôi không thể thêm một người tham gia sự kiện sau khi tải đã được kích hoạt vì nó sẽ không được gọi. Vì vậy, làm thế nào tôi có thể kiểm tra nếu tài liệu đã được tải? Tôi đã thử mã dưới đây nhưng nó không hoàn toàn hoạt động. Có ý kiến ​​gì không?

var body = document.getElementsByTagName('BODY')[0];
// CONDITION DOES NOT WORK
if (body && body.readyState == 'loaded') {
    DoStuffFunction();
} else {
    // CODE BELOW WORKS
    if (window.addEventListener) {  
        window.addEventListener('load', DoStuffFunction, false);
    } else {
        window.attachEvent('onload', DoStuffFunction);
    }
}

5
"Tôi muốn gọi một chức năng sau khi tải tài liệu, nhưng tài liệu có thể hoặc chưa tải xong." Điều này không tính toán.
Richard Simões

7
Tôi tin rằng anh ta có nghĩa là anh ta không có quyền kiểm soát khi khối mã của anh ta ban đầu được chạy, nhưng muốn đảm bảo DoStuffFunction () không được gọi trước khi tài liệu tải xong.
Ben Trống

Câu trả lời:


257

Không cần tất cả các mã được đề cập bởi galambalazs. Cách trình duyệt chéo để thực hiện điều đó trong JavaScript thuần túy chỉ đơn giản là kiểm tra document.readyState:

if (document.readyState === "complete") { init(); }

Đây cũng là cách jQuery làm điều đó.

Tùy thuộc vào nơi JavaScript được tải, điều này có thể được thực hiện trong một khoảng:

var readyStateCheckInterval = setInterval(function() {
    if (document.readyState === "complete") {
        clearInterval(readyStateCheckInterval);
        init();
    }
}, 10);

Trong thực tế, document.readyStatecó thể có ba trạng thái:

Trả về "đang tải" trong khi tài liệu đang tải, "tương tác" sau khi hoàn thành phân tích cú pháp nhưng vẫn tải tài nguyên phụ và "hoàn thành" khi đã tải xong. - document. yetState tại Mozilla Developer Network

Vì vậy, nếu bạn chỉ cần DOM để sẵn sàng, hãy kiểm tra document.readyState === "interactive". Nếu bạn cần toàn bộ trang để sẵn sàng, bao gồm cả hình ảnh, hãy kiểm tra document.readyState === "complete".


3
@costa, nếu document.readyState == "complete", nó có nghĩa là tất cả mọi thứ, bao gồm cả hình ảnh, đã được tải.
laurent

Tôi đang sử dụng kết hợp cả hai sự kiện và document.readyStateđể đảm bảo chức năng bắt đầu sau khi DOM được phân tích cú pháp, hoặc sau đó, tùy thuộc vào thời điểm nó được gọi. Có một sự kiện cho tương tác readyState ?
Tomáš Zato - Phục hồi Monica

3
Tôi sẽ sử dụng /loaded|complete/.test(document.readyState). Một số trình duyệt được đặt document.readyStatethành "đã tải" thay vì "hoàn tất". Ngoài ra, document. YetState KHÔNG đảm bảo phông chữ đã được tải, không có cách nào thực sự tốt để kiểm tra mà không có plugin.
Ryan Taylor

2
Thế còn document.onreadystatechange? Điều này có vẻ hợp lý hơn nếu các trình duyệt hỗ trợ nó. stackoverflow.com/questions/807878/

2
Tôi nghĩ sẽ tốt hơn nếu kiểm tra document.readyState !== "loading"trạng thái "sẵn sàng DOM". Điều này ngăn chặn các vấn đề cắt xén nếu readyStateđược kiểm tra muộn vì một số lý do (sau trạng thái "tương tác").
rnevius

32

Không cần thư viện. jQuery đã sử dụng tập lệnh này trong một thời gian, btw.

http://dean.edwards.name/weblog/2006/06/again/

// Dean Edwards/Matthias Miller/John Resig

function init() {
  // quit if this function has already been called
  if (arguments.callee.done) return;

  // flag this function so we don't do the same thing twice
  arguments.callee.done = true;

  // kill the timer
  if (_timer) clearInterval(_timer);

  // do stuff
};

/* for Mozilla/Opera9 */
if (document.addEventListener) {
  document.addEventListener("DOMContentLoaded", init, false);
}

/* for Internet Explorer */
/*@cc_on @*/
/*@if (@_win32)
  document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
  var script = document.getElementById("__ie_onload");
  script.onreadystatechange = function() {
    if (this.readyState == "complete") {
      init(); // call the onload handler
    }
  };
/*@end @*/

/* for Safari */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
  var _timer = setInterval(function() {
    if (/loaded|complete/.test(document.readyState)) {
      init(); // call the onload handler
    }
  }, 10);
}

/* for other browsers */
window.onload = init;

1
Chính xác những gì tôi đang tìm kiếm - Hàm jQuery. Yet không có thư viện jQuery. Thanx!
stricjux

3
Hoàn toàn bỏ lỡ điểm của câu hỏi. initsẽ không chạy nếu mã này bạn đã đăng được đưa vào sau khi trang đã được tải, đó là điểm của OP: anh ấy / cô ấy không thể kiểm soát khi bao gồm tập lệnh của mình. (lưu ý rằng chỉ có setIntervalchi nhánh sẽ hoạt động)
Roatin Marth

3
Điều này thuộc về một thư viện. Cùng với tất cả các bánh xe khác mọi người thường phát minh lại.
b01

14

Bạn có thể muốn sử dụng một cái gì đó như jQuery, điều này làm cho việc lập trình JS dễ dàng hơn.

Cái gì đó như:

$(document).ready(function(){
   // Your code here
});

Dường như sẽ làm những gì bạn đang sau.


2
Và nếu anh ta muốn xem jQuery làm điều đó theo cách di động, nguồn của jQuery có sẵn để kiểm tra :-)
Thomas L Holaday

7
Và trong trường hợp không rõ ràng, nếu ready()được gọi sau khi tải tài liệu, hàm được truyền sẽ chạy ngay lập tức.
Ben Trống

2
@Ben Trống: trừ khi tất nhiên bản thân jQuery được bao gồm sau khi tài liệu được tải;)
Roatin Marth

@Roatin Marth - Thật ra, nó cũng hoạt động tốt. (Chỉ dùng thử với jQuery 1.7.1 trên FF8 và IE8.)
Ben Blank

35
-1: ngay cả khi câu trả lời hợp lý, OP không bao giờ đề cập đến jQuery. Sử dụng toàn bộ dự án jQuery chỉ để chuẩn bị tài liệu là cách quá mức cần thiết.
marcgg

8
if(document.readyState === 'complete') {
    DoStuffFunction();
} else {
    if (window.addEventListener) {  
        window.addEventListener('load', DoStuffFunction, false);
    } else {
        window.attachEvent('onload', DoStuffFunction);
    }
}

Dường như không hoạt động trong Chrome mới nhất document.loadedluôn không được xác định
Aniket

đây là năm 2010 :). Bây giờ tôi sẽ sử dụngbody.readyState === 'loaded'
Jman

6

Nếu bạn thực sự muốn mã này chạy khi tải , không phải ở trạng thái sẵn sàng (tức là bạn cũng cần tải hình ảnh), thì thật không may, chức năng sẵn sàng không làm điều đó cho bạn. Tôi thường chỉ làm một cái gì đó như thế này:

Bao gồm trong javascript tài liệu (nghĩa là luôn được gọi trước khi tải onload):

var pageisloaded=0;
window.addEvent('load',function(){
 pageisloaded=1;
});

Sau đó, mã của bạn:

if (pageisloaded) {
 DoStuffFunction();
} else {
 window.addEvent('load',DoStuffFunction);
}

(Hoặc tương đương trong khung ưu tiên của bạn.) Tôi sử dụng mã này để thực hiện việc nhập trước javascript và hình ảnh cho các trang trong tương lai. Vì những thứ tôi nhận được không được sử dụng cho trang này, tôi không muốn nó được ưu tiên trong việc tải xuống hình ảnh nhanh chóng.

Có thể có một cách tốt hơn, nhưng tôi vẫn chưa tìm thấy nó.


4

Mozila Firefox nói rằng đó onreadystatechangelà một thay thế cho DOMContentLoaded.

// alternative to DOMContentLoaded
document.onreadystatechange = function () {
    if (document.readyState == "complete") {
        initApplication();
    }
}

Trong DOMContentLoadedtài liệu của Mozila nói:

Sự kiện DOMContentLoaded được kích hoạt khi tài liệu đã được tải và phân tích cú pháp hoàn toàn, không cần chờ biểu định kiểu, hình ảnh và khung con để tải xong (sự kiện tải có thể được sử dụng để phát hiện trang được tải đầy đủ).

Tôi nghĩ rằng loadsự kiện nên được sử dụng cho một tài liệu đầy đủ + tải tài nguyên.


3

Cách trên với JQuery là cách dễ nhất và được sử dụng nhiều nhất. Tuy nhiên, bạn có thể sử dụng javascript thuần túy nhưng cố gắng xác định tập lệnh này trong phần đầu để nó được đọc ở đầu. Những gì bạn đang tìm kiếm là window.onloadsự kiện.

Dưới đây là một tập lệnh đơn giản mà tôi đã tạo để chạy bộ đếm. Bộ đếm sau đó dừng lại sau 10 lần lặp

window.onload=function()
{
    var counter = 0;
    var interval1 = setInterval(function()
    { 
        document.getElementById("div1").textContent=counter;
        counter++; 
        if(counter==10)
        {
            clearInterval(interval1);
        }
    },1000);

}

2

Thử cái này:

var body = document.getElementsByTagName('BODY')[0];
// CONDITION DOES NOT WORK
if ((body && body.readyState == 'loaded') || (body &&  body.readyState == 'complete') ) {
    DoStuffFunction();
} else {
    // CODE BELOW WORKS
    if (window.addEventListener) {
        window.addEventListener('load', DoStuffFunction, false);
    } else {
        window.attachEvent('onload',DoStuffFunction);
    }
}

1

Tôi có một giải pháp khác, ứng dụng của tôi cần được khởi động khi đối tượng mới của MyApp được tạo, vì vậy nó trông giống như:

function MyApp(objId){
     this.init=function(){
        //.........
     }
     this.run=function(){
          if(!document || !document.body || !window[objId]){
              window.setTimeout(objId+".run();",100);
              return;
          }
          this.init();
     };
     this.run();
}
//and i am starting it 
var app=new MyApp('app');

Nó đang làm việc trên tất cả các trình duyệt, mà tôi biết.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.