Как проверить, загружен ли iframe или есть контент?

84

У меня есть 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(){}).

новичок29
источник
Значит, вы не хотите, чтобы iframe загружал что-либо, если загрузка занимает более 5 секунд?
skimberk1
Спасибо за вашу помощь :) . Да, я не хочу, чтобы iframe загружал что-либо, если загрузка занимает более 5 секунд. Использование ".ready ()", как показано ниже, не работает.
newbie29
См. Мой ответ здесь stackoverflow.com/questions/17158932/…
чувак
Проверьте этот ответ - forum.tumult.com/t/detect-iframe-loaded/7588
Varshaan

Ответы:

89

Попробуй это.

<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. Домены, протоколы и порты должны совпадать».
Мохамед-Ибрахим
Это было лучшее решение для того, что я пытался сделать. Я использую AngularJS внутри iFrame и использую ng-include, что задерживает загрузку включенных файлов. Я пытался распечатать содержимое iframe при событии onload, но он запускался слишком рано. Проверка на readyState === "complete"сработала, поскольку она не меняется, пока все не загрузится.
Джеффри А. Гочин,
3
Я должен сказать, что это было единственное решение, которое сработало и для меня. Вы просто не можете доверять событию load в iframe, поскольку в большинстве случаев в IE11, Chrome и Edge оно срабатывает сразу же с iframe.contentDocument.location.hrefотображением как about:blank. Это кажется правдой, даже если srcдля iframeуказывается непосредственно в HTML.
rmalayter
24
Это не сработает, если iframe поступает из другого домена:VM29320:1 Uncaught DOMException: Blocked a frame with origin "http://localhost:9002" from accessing a cross-origin frame.
Августин Ридинджер,
46

любезно используйте:

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

Обновил свой ответ по мере изменения стандартов.

пратикабу
источник
4
Этот подход вообще не работает, поскольку событие запускается немедленно, потому что iframes обычно начинается с src="about:blank", даже если srcон указан непосредственно в HTML или до того, как iframeузел будет добавлен в DOM. Я проверил это путем опроса для iframe«с 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
Пожалуйста, подумайте о редактировании вашего сообщения, чтобы добавить больше объяснений о том, что делает ваш код и почему он решает проблему. Ответ, который в основном содержит просто код (даже если он работает), обычно не поможет OP понять их проблему.
SuperBiasedMan
5

Я не уверен, сможете ли вы определить, загружен он или нет, но вы можете запустить событие, как только оно загрузится:

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

РЕДАКТИРОВАТЬ: как указал Джесси Халлетт, это всегда срабатывает, когда iframeзагружается, даже если он уже был. По сути, если iframeуже загружен, обратный вызов будет выполнен немедленно.

skimberk1
источник
2
Хорошая особенность этого метода заключается в том, что событие jQuery 'ready' будет срабатывать, даже если вы привяжете его после полной загрузки iframe. Так что это хороший способ проверить, есть ли уже у iframe контент, или уведомить вас, когда он получит контент.
Джесси Халлетт
1
Кажется, это срабатывает только один раз для iframe. Однако, если в вашем iframe есть ссылки, которые могут привести к перезагрузке содержимого в iframe, это событие больше не сработает. Если это ваш случай, используйте ответ @pratikabu -$('#myIframe').load(function(){ })
ragamufin
@ skimberk1 Привет, в соответствии с этим ответом ваше решение не будет работать, потому что jquery содержит переменную, чтобы помнить, загружена ли DOM, и onley проверяет текущую DOM текущего кадра, а не DOM iframe.
Марко Медрано
да, вы можете запускать события, показывать видео,
включать
Согласно этому тикету : 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 может быть В ПРОЦЕССЕ загрузки (загружен не полностью).
Майк Шиян
1

У меня есть трюк, который работает следующим образом: [кроссбраузерность не тестировалась!]

Определите обработчик события onload 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);

});

Заявление об ограничении ответственности: работает только с документами IFRAME с одинаковым происхождением.

Пратап Сингх
источник
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прослушиватель событий к iframeWindow .

Учитывая, что у вас есть 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!');
    });
});
Даниэль
источник