Як перевірити, чи завантажено iframe чи він має вміст?


83

У мене є iframe з id = "myIframe", і тут мій код для завантаження його вмісту:

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

Проблема полягає в тому, що завантаження триває занадто довго, а іноді завантажується дуже швидко. Тому я повинен використовувати функцію "setTimeout":

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

Все, що я хочу знати, це те, як дізнатись, чи завантажується iFrame, чи він містить вміст. Використання iframe.contents().find()не буде працювати. Я не можу використовувати iframe.load(function(){}).


Отже, ви не хочете, щоб iframe щось завантажував, якщо завантаження займає більше 5 секунд?
skimberk1

Спасибі за вашу допомогу :) . Так, я не хочу нічого завантажувати, якщо завантаження займає більше 5 секунд. Використання ".ready ()", як показано нижче, не працює.
новачок29,

Дивіться мою відповідь тут stackoverflow.com/questions/17158932/…
чувак

Перевірте цей відповідь - forums.tumult.com/t/detect-iframe-loaded/7588
Varshaan

Відповіді:


88

Спробуйте це.

<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
Деменції для передачі рядка в setTimeout (). Чистіше передавати посилання на функцію:setTimeout(checkIframeLoaded, 100);
Джессі Халлетт

1
це призвело до "Небезпечної спроби JavaScript отримати доступ до фрейму з URL-адресою url1 з фрейму з url2. Домени, протоколи та порти повинні збігатися."
mohamed-ibrahim

Це було найкраще рішення для того, що я намагався досягти. Я використовую AngularJS всередині iFrame та використовую ng-include, що затримує завантаження включених файлів. Я намагався надрукувати вміст Iframe під час завантаження, але це спрацювало занадто рано. Перевірка на те, що readyState === "complete"зробила трюк, оскільки вона не змінюється, поки все не завантажується.
Jeffrey A. Gochin

3
Я повинен сказати, що це було єдине рішення, яке спрацювало і для мене. Ви просто не можете довіряти події завантаження на iframe, оскільки вона запускається негайно, в більшості випадків на IE11, Chrome та Edge із iframe.contentDocument.location.hrefвідображенням як about:blank. Це, здається, відповідає дійсності, навіть якщо srcfor iframeвказано безпосередньо в HTML.
rmalayter

21
Це не спрацює, якщо iframe походить з іншого домену:VM29320:1 Uncaught DOMException: Blocked a frame with origin "http://localhost:9002" from accessing a cross-origin frame.
Августин Рідінгер,

45

ласкаво використовуйте:

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

Оновив свою відповідь у міру зміни стандартів.


5
Виклик .load тепер застарілий. Замість цього використовуйте .on ('load', function () {})
Грем

51
Виклик jQuery тепер застарілий ^^
cchamberlain

4
Цей підхід взагалі не працює, оскільки подія запускається негайно, тому що iframes зазвичай починається з src="about:blank", навіть якщо значення srcвказано безпосередньо в HTML або до iframeдодавання вузла до DOM. Я перевірив це, опитуючи iframe's' contentDocument.location.hrefв щільному циклі на IE11, Chrome та Edge. Це також не працює, якщо вміст, який оформляється, переспрямовує через мета-теги або javascript.
rmalayter

17

У мене була та ж проблема, і я додав до неї, що мені потрібно було перевірити, чи завантажується iframe незалежно від міждоменної політики. Я розробляв розширення chrome, яке вводить певний сценарій на веб-сторінку та відображає деякий вміст із батьківської сторінки у iframe. Я спробував наступний підхід, і це мені вдалося.
PS: У моєму випадку я контролюю вміст у iframe, але не на батьківському сайті. (Iframe розміщується на моєму власному сервері)

По-перше:
Створіть iframe з data-атрибутом у ньому, наприклад (ця частина в моєму випадку була введеним скриптом)
<iframe id="myiframe" src="http://anyurl.com" data-isloaded="0"></iframe>

Тепер у коді iframe використовуйте:

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



Тепер повернімось до введеного сценарію відповідно до мого випадку:

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);


і,

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');
        }
    }           
}



Це може не точно відповісти на питання, але це справді можливий випадок цього питання, який я вирішив цим методом.


У вашому коді є деякі помилки, наприклад document.getElement-> s <-ById, але вся ідея корисна. Це працює. Спасибі)
JohnK

@JohnK Дякую, що вказав на це, я це виправив. Радий знати, що це корисно для вас.
Тушар Шукла,

12

Найпростіший варіант:

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

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

10
не є твердим рішенням, оскільки він видає попередження, навіть якщо URL-адреса порушена.
bboy

7

Ви можете використовувати loadподію iframe, щоб відповісти, коли iframe завантажується.

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

Це не скаже вам, чи завантажено правильний вміст: щоб перевірити це, ви можете перевірити файл contentDocument.

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

Перевірка contentDocumentне буде працювати, якщо iframe srcвказує на інший домен, де працює ваш код.


2
Будь ласка, подумайте про редагування вашого допису, щоб додати більше пояснень щодо того, що робить ваш код, і чому це вирішить проблему. Відповідь, яка здебільшого містить лише код (навіть якщо він працює), як правило, не допомагає ОП зрозуміти свою проблему.
SuperBiased,

5

Я не впевнений, чи можете ви виявити, чи завантажується він чи ні, але ви можете запустити подію, як тільки завантаження завершиться:

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

РЕДАГУВАТИ: Як зазначив Джессі Халлетт, це спрацьовуватиме завжди, коли iframeфайл завантажується, навіть якщо він уже є. Отже, по суті, якщо iframeвже завантажено, зворотний виклик буде виконано негайно.


2
Приємним у цьому методі є те, що подія jQuery 'готовий' спрацює, навіть якщо ви прив'яжете його після повного завантаження iframe. Тож це хороший спосіб перевірити, чи вже має вміст iframe, або повідомити вас про отримання вмісту.
Джессі Халлетт,

1
Здається, це запускається лише один раз для iframe. Однак якщо у вашому iframe є посилання, що може призвести до перезавантаження вмісту в iframe, ця подія не запускатиметься знову. Якщо це ваш випадок, тоді використовуйте відповідь @pratikabu -$('#myIframe').load(function(){ })
ragamufin

@ skimberk1 Привіт, згідно з цією відповіддю ваше рішення не працюватиме, оскільки jquery містить змінну, щоб запам'ятати, чи було завантажено DOM, і onley перевіряє поточний DOM поточного кадру, а не DOM iframe.
Marco Medrano

так, ви можете запускати події, показувати відео, відтворювати музику, коли це буде готово, дуже інформативно ....
Гірідхар Карнік

Відповідно до цього квитка: dev.jquery.com/ticket/5511 використання readyв iframe завжди буде негайно виконувати функцію, оскільки вона не підтримується іншими документами, ніж фрейм, в якому запущений jQuery.
чувак,

5

у моєму випадку це був фрейм із перехресним походженням, який іноді не завантажувався. рішення, яке працювало для мене: якщо він успішно завантажений, то якщо ви спробуєте цей код:

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

це не дозволить вам отримати доступ contentDocumentі викинути помилку перехресного походження, однак якщо кадр не завантажено успішно, то contentDocumentповерне #documentоб'єкт


2

Коли iFrame завантажується, він спочатку містить #document, тому перевірка стану завантаження може найкраще спрацювати, перевіривши, що там зараз ..

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

6
Це не вдасться, якщо він знаходиться в іншому домені
Funkodebat

Це неправильно, оскільки iframe може бути В ПРОЦЕСІ завантаження (не повністю завантажений).
Mike Shiyan,

1

Я отримав фокус, який працює наступним чином: [не тестували крос-браузер!]

Визначте обробник події завантаження iframe, визначений як

$('#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);

});

Застереження: це працює лише для тих самих документів з тим самим походженням.


0

Дійсно чудовим методом є використання jQuery AJAX. Батьківський кадр буде виглядати так:

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

Файл iframe_load.php завантажує бібліотеку jQuery та JavaScript, який намагається завантажити цільову URL-адресу в 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' ) ;
            } });

ВАЖЛИВО Місце призначення повинно містити заголовок "Access-Control-Allow-Origin". Приклад в PHP:

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

0

Якщо вам потрібно знати, коли iframe готовий до маніпуляцій, використовуйте інтервал. У цьому випадку я "пінгую" вміст кожні 250 мс, і якщо в цільовому фреймі є якийсь вміст, зупиніть "пінг" і зробіть щось.

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

Якщо ви розміщуєте сторінку та iframe в одному домені, ви можете прослухати Window.DOMContentLoadedподію iframe . Спочатку потрібно зачекати, поки оригінальна сторінка запуститься DOMContentLoaded, а потім приєднати DOMContentLoadedпрослуховувач подій до iframe Window.

З огляду на те, що у вас є такий iframe,

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

наступний фрагмент дозволить вам підключитися до DOMContentLoadedподії 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!');
    });
});
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.