Làm thế nào để kiểm tra xem iframe đã được tải hoặc nó có nội dung?


83

Tôi có iframe với id = "myIframe" và đây là mã của tôi để tải nội dung của nó:

$('#myIframe').attr("src", "my_url");

Vấn đề là đôi khi tải quá lâu và đôi khi tải rất nhanh. Vì vậy, tôi phải sử dụng chức năng "setTimeout":

setTimeout(function(){
   if (//something shows iframe is loaded or has content)
   {
       //my code
   }
   else
   {
       $('#myIframe').attr("src",""); //stop loading content
   }
},5000);

Tất cả những gì tôi muốn biết là làm thế nào để tìm hiểu xem một iFrame đã được tải hay nó có nội dung. Sử dụng iframe.contents().find()sẽ không hoạt động. Tôi không thể sử dụng iframe.load(function(){}).


Vì vậy, bạn không muốn iframe tải bất cứ thứ gì nếu mất hơn 5 giây để tải?
skimberk1

Cảm ơn bạn đã giúp đỡ :) . Có, tôi không muốn iframe tải bất kỳ thứ gì nếu mất hơn 5 giây để tải. Sử dụng ".ready ()" như bạn hiển thị dưới đây không hoạt động.
newbie29

Xem câu trả lời của tôi tại đây stackoverflow.com/questions/17158932/…
anh bạn

Kiểm tra câu trả lời này - Forum.tumult.com/t/detect-iframe-loaded/7588
Varshaan

Câu trả lời:


88

Thử đi.

<script>
function checkIframeLoaded() {
    // Get a handle to the iframe element
    var iframe = document.getElementById('i_frame');
    var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;

    // Check if loading is complete
    if (  iframeDoc.readyState  == 'complete' ) {
        //iframe.contentWindow.alert("Hello");
        iframe.contentWindow.onload = function(){
            alert("I am loaded");
        };
        // The loading is complete, call the function we want executed once the iframe is loaded
        afterLoading();
        return;
    } 

    // If we are here, it is not loaded. Set things up so we check   the status again in 100 milliseconds
    window.setTimeout(checkIframeLoaded, 100);
}

function afterLoading(){
    alert("I am here");
}
</script>

<body onload="checkIframeLoaded();"> 

21
Phần thưởng cho việc truyền một chuỗi tới setTimeout (). Sẽ rõ ràng hơn nếu chuyển một tham chiếu hàm:setTimeout(checkIframeLoaded, 100);
Jesse Hallett

1
điều này dẫn đến "JavaScript không an toàn cố gắng truy cập khung có URL url1 từ khung có url2 Miền, giao thức và cổng phải khớp."
mohamed-ibrahim

Đây là giải pháp tốt nhất cho những gì tôi đang cố gắng hoàn thành. Tôi đang sử dụng AngularJS bên trong iFrame và sử dụng ng-include, điều này sẽ làm chậm quá trình tải các tệp được bao gồm. Tôi đang cố in nội dung của Iframe khi sự kiện tải lên, nhưng nó đã hoạt động quá sớm. Kiểm tra xem có readyState === "complete"phải là mẹo, vì nó không thay đổi cho đến khi mọi thứ được tải.
Jeffrey A. Gochin,

3
Tôi phải nói rằng đây là giải pháp duy nhất phù hợp với tôi. Bạn chỉ không thể tin tưởng sự kiện tải trên iframe, vì nó kích hoạt ngay lập tức trong hầu hết các trường hợp trên IE11, Chrome và Edge với iframe.contentDocument.location.hrefhiển thị là about:blank. Điều này có vẻ đúng ngay cả khi srcfor iframeđược chỉ định trực tiếp trong HTML.
rmalayter

21
Điều này sẽ không hoạt động nếu iframe đến từ một miền khác:VM29320:1 Uncaught DOMException: Blocked a frame with origin "http://localhost:9002" from accessing a cross-origin frame.
Augustin Riedinger,

45

vui lòng sử dụng:

$('#myIframe').on('load', function(){
    //your code (will be called once iframe is done loading)
});

Đã cập nhật câu trả lời của tôi khi các tiêu chuẩn thay đổi.


5
Gọi .load hiện không được dùng nữa .. Sử dụng .on ('load', function () {}) thay thế
Graham T

51
Gọi jQuery hiện không được dùng nữa ^^
cchamberlain

4
Cách tiếp cận này hoàn toàn không hoạt động khi sự kiện kích hoạt ngay lập tức vì iframethường bắt đầu bằng src="about:blank", ngay cả khi srcnó được chỉ định trực tiếp trong HTML hoặc trước khi một iframenút được thêm vào DOM. Tôi đã thử nghiệm điều này bằng cách bỏ phiếu cho iframe's contentDocument.location.hreftrong một vòng lặp chặt chẽ trên IE11, Chrome, và Edge. Nó cũng không hoạt động nếu nội dung được đóng khung chuyển hướng qua thẻ meta hoặc javascript.
rmalayter

17

Tôi đã gặp vấn đề tương tự và đã thêm vào vấn đề này, tôi cần kiểm tra xem iframe có được tải không bất kể chính sách tên miền chéo. Tôi đang phát triển một tiện ích mở rộng chrome đưa một tập lệnh nhất định vào một trang web và hiển thị một số nội dung từ trang chính trong iframe. Tôi đã thử làm theo cách tiếp cận và điều này hoàn toàn phù hợp với tôi.
Tái bút: Trong trường hợp của tôi, tôi có quyền kiểm soát nội dung trong iframe nhưng không có trên trang web mẹ. (Iframe được lưu trữ trên máy chủ của riêng tôi)

Đầu tiên:
Tạo iframe với data-thuộc tính trong đó như (phần này nằm trong tập lệnh được chèn trong trường hợp của tôi)
<iframe id="myiframe" src="http://anyurl.com" data-isloaded="0"></iframe>

Bây giờ trong mã iframe, hãy sử dụng:

var sourceURL = document.referrer;
window.parent.postMessage('1',sourceURL);



Bây giờ quay lại tập lệnh được chèn theo trường hợp của tôi:

setTimeout(function(){
  var myIframe = document.getElementById('myiframe');
  var isLoaded = myIframe.prop('data-isloaded');
  if(isLoaded != '1')
  {
    console.log('iframe failed to load');
  } else {
    console.log('iframe loaded');
  }
},3000);


và,

window.addEventListener("message", receiveMessage, false);
function receiveMessage(event)
{
    if(event.origin !== 'https://someWebsite.com') //check origin of message for security reasons
    {
        console.log('URL issues');
        return;
    }
    else {
        var myMsg = event.data;
        if(myMsg == '1'){
            //8-12-18 changed from 'data-isload' to 'data-isloaded
            $("#myiframe").prop('data-isloaded', '1');
        }
    }           
}



Nó có thể không trả lời chính xác câu hỏi nhưng nó thực sự là một trường hợp có thể xảy ra với câu hỏi này mà tôi đã giải quyết bằng phương pháp này.


Có một số lỗi trong mã của bạn, như document.getElement-> s <-ById, nhưng toàn bộ ý tưởng đều hữu ích. Nó hoạt động. Cảm ơn)
JohnK

@JohnK Cảm ơn bạn đã chỉ ra điều đó, tôi đã sửa nó. Rất vui khi biết điều này hữu ích cho bạn.
Tushar Shukla

12

Tùy chọn dễ nhất:

<script type="text/javascript">
  function frameload(){
   alert("iframe loaded")
  }
</script>

<iframe onload="frameload()" src=...>

10
không phải là một giải pháp rắn vì nó đưa ra cảnh báo ngay cả khi url bị hỏng.
bboy,

7

Bạn có thể sử dụng loadsự kiện của iframe để phản hồi khi iframe tải.

document.querySelector('iframe').onload = function(){
    console.log('iframe loaded');
};

Điều này sẽ không cho bạn biết liệu nội dung chính xác được tải hay không: Để kiểm tra điều đó, bạn có thể kiểm tra contentDocument.

document.querySelector('iframe').onload = function(){
    var iframeBody = this.contentDocument.body;
    console.log('iframe loaded, body is: ', body);
};

Việc kiểm tra contentDocumentsẽ không hoạt động nếu iframe srctrỏ đến một miền khác với nơi mã của bạn đang chạy.


2
Vui lòng xem xét chỉnh sửa bài đăng của bạn để thêm giải thích về những gì mã của bạn làm và tại sao nó sẽ giải quyết vấn đề. Một câu trả lời chủ yếu chỉ chứa mã (ngay cả khi nó đang hoạt động) thường không giúp OP hiểu được vấn đề của họ.
SuperBiasedMan

5

Tôi không chắc liệu bạn có thể phát hiện ra nó đã được tải hay chưa, nhưng bạn có thể kích hoạt một sự kiện sau khi tải xong:

$(function(){
    $('#myIframe').ready(function(){
        //your code (will be called once iframe is done loading)
    });
});

CHỈNH SỬA: Như Jesse Hallett đã chỉ ra, điều này sẽ luôn kích hoạt khi iframeđã được tải, ngay cả khi nó đã có. Vì vậy, về cơ bản, nếu iframeđã được tải, lệnh gọi lại sẽ thực thi ngay lập tức.


2
Điều thú vị về phương pháp này là sự kiện jQuery 'ready' sẽ kích hoạt ngay cả khi bạn liên kết nó sau khi iframe được tải hoàn toàn. Vì vậy, đó là một cách tốt để kiểm tra xem iframe đã có nội dung hay chưa hoặc thông báo cho bạn khi có nội dung.
Jesse Hallett

1
Điều này dường như chỉ kích hoạt một lần cho iframe. Tuy nhiên, nếu iframe của bạn có các liên kết trong đó có thể dẫn đến nội dung trong iframe được tải lại thì sự kiện này sẽ không kích hoạt lại. Nếu đây là trường hợp của bạn sau đó sử dụng các câu trả lời bằng @pratikabu -$('#myIframe').load(function(){ })
ragamufin

@ skimberk1 Xin chào, theo câu trả lời này, giải pháp của bạn sẽ không hoạt động, bởi vì jquery giữ một biến để nhớ xem DOM đã được tải chưa và onley kiểm tra DOM hiện tại của khung hiện tại không phải là DOM của iframe.
Marco Medrano

vâng, bạn có thể kích hoạt các sự kiện, hiển thị video, phát nhạc khi nó đã sẵn sàng, rất nhiều thông tin ....
Giridhar Karnik

Theo vé này: dev.jquery.com/ticket/5511 sử dụng readytrên iframe sẽ luôn thực thi ngay lập tức hàm, vì nó không được hỗ trợ cho các tài liệu khác khi khung mà jQuery đang chạy.
dude

5

trong trường hợp của tôi, đó là một khung gốc chéo và đôi khi không tải. giải pháp phù hợp với tôi là: nếu nó được tải thành công thì nếu bạn thử mã này:

var iframe = document.getElementsByTagName('iframe')[0];
console.log(iframe.contentDocument);

nó sẽ không cho phép bạn truy cập contentDocumentvà gây ra lỗi cross-origin, tuy nhiên, nếu frame không được tải thành công thì nó contentDocumentsẽ trả về một #documentđối tượng


2

Khi một iFrame tải, ban đầu nó chứa #document, vì vậy việc kiểm tra trạng thái tải có thể hoạt động tốt nhất bằng cách kiểm tra những gì hiện có ..

if ($('iframe').contents().find('body').children().length > 0) {
    // is loaded
} else {
    // is not loaded
}

6
Điều này sẽ không thành công nếu nó nằm trên một miền khác
Funkodebat

Điều này không chính xác, bởi vì iframe có thể đang trong quá trình tải (chưa tải hoàn toàn).
Mike Shiyan

1

Tôi có một mẹo hoạt động như sau: [chưa thử nghiệm trình duyệt chéo!]

Xác định trình xử lý sự kiện onload của iframe được xác định là

$('#myIframe').on('load', function() {
    setTimeout(function() {
        try {
            console.log($('#myIframe')[0].contentWindow.document);
        } catch (e) {
            console.log(e);
            if (e.message.indexOf('Blocked a frame with origin') > -1 || e.message.indexOf('from accessing a cross-origin frame.') > -1) {
                alert('Same origin Iframe error found!!!');
                //Do fallback handling if you want here
            }
        }
    }, 1000);

});

Tuyên bố từ chối trách nhiệm: Nó chỉ hoạt động cho các tài liệu IFRAME CÙNG GỐC.


0

Một phương pháp thực sự tuyệt vời là sử dụng jQuery AJAX. Khung cha sẽ trông như thế này:

<iframe src="iframe_load.php" style="width: 100%; height: 100%;"></iframe>

Tệp iframe_load.php sẽ tải thư viện jQuery và một JavaScript cố gắng tải URL đích trong AJAX GET:

var the_url_to_load = "http://www.your-website.com" ;
$.ajax({
            type: "GET",
            url: the_url_to_load,
            data: "",
            success: function(data){
                // if can load inside iframe, load the URL
                location.href = the_url_to_load ;
            },
            statusCode: {
                500: function() {
                    alert( 'site has errors' ) ;
                }
            },
            error:function (xhr, ajaxOptions, thrownError){
                // if x-frame-options, site is down or web server is down
                alert( 'URL did not load due to x-frame-options' ) ;
            } });

QUAN TRỌNG Đích đến phải chứa tiêu đề "Access-Control-Allow-Origin". Ví dụ trong PHP:

HEADER( "Access-Control-Allow-Origin: *" ) ;

0

Nếu bạn cần biết khi nào iframe sẵn sàng thao tác, hãy sử dụng một khoảng thời gian. Trong trường hợp này, tôi "ping" nội dung cứ sau 250 mili giây và nếu có bất kỳ nội dung nào bên trong iframe mục tiêu, hãy dừng "ping" và làm điều gì đó.

var checkIframeLoadedInterval = setInterval( checkIframeLoaded, 250 );

function checkIframeLoaded() {
    var iframe_content = $('iframe').contents();

    if (iframe_content.length > 0) {
        clearInterval(checkIframeLoadedInterval);

        //Apply styles to the button
        setTimeout(function () {
            //Do something inside the iframe 
            iframe_content.find("body .whatever").css("background-color", "red");
        }, 100); //100 ms of grace time
    }
}

0

Nếu bạn đang lưu trữ trang và iframe trên cùng một miền, bạn có thể nghe Window.DOMContentLoadedsự kiện của iframe . Trước tiên, bạn phải đợi trang gốc kích hoạt DOMContentLoaded, sau đó đính kèm trình xử lý DOMContentLoadedsự kiện trên iframe củaWindow .

Cho bạn có một iframe như sau,

<iframe id="iframe-id" name="iframe-name" src="..."></iframe>

đoạn mã tiếp theo sẽ cho phép bạn tham gia vào DOMContentLoadedsự kiện của iframe :

document.addEventListener('DOMContentLoaded', function () {
    var iframeWindow = frames['iframe-name'];
    // var iframeWindow = document.querySelector('#iframe-id').contentWindow
    // var iframeWindow = document.getElementById('iframe-id').contentWindow

    iframeWindow.addEventListener('DOMContentLoaded', function () {
        console.log('iframe DOM is loaded!');
    });
});
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.