Як перевірити, чи завантажено 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.