Обратный вызов Javascript после завершения загрузки IFRAME?


147

Мне нужно выполнить обратный вызов, когда загрузка IFRAME закончилась. Я не контролирую содержимое в IFRAME, поэтому не могу запустить обратный вызов оттуда.

Этот IFRAME создается программно, и мне нужно передать его данные в качестве переменной в обратном вызове, а также уничтожить iframe.

Любые идеи?

РЕДАКТИРОВАТЬ:

Вот что у меня сейчас:

function xssRequest(url, callback)
{
    var iFrameObj = document.createElement('IFRAME');
    iFrameObj.src = url;            
    document.body.appendChild(iFrameObj);   

    $(iFrameObj).load(function() 
    {
        document.body.removeChild(iFrameObj);
        callback(iFrameObj.innerHTML);
    });
}

Этот обратный вызов перед загрузкой iFrame, поэтому данные обратного вызова не возвращаются.


1
Я думаю, что вы не хотите прикреплять обработчик событий к самому iframe, но это окно содержимого.
bobwienholt

1
Проблема заключается в междоменном запросе. Вы не можете сделать это, если iframe из другого домена
Виктор

На самом деле, существует событие load для объекта iframe, которое запускается каждый раз, когда iframe завершает загрузку документа, в противном случае вам нужно будет подключиться к окну после каждой загрузки
Хуан Мендес,


Смотрите мой ответ здесь: stackoverflow.com/a/36155560/3894981
чувак

Ответы:


49

Во-первых, переходя к названию функции xssRequest, это звучит так, как будто вы пытаетесь выполнить межсайтовый запрос - что, если это правильно, вы не сможете прочитать содержимое iframe.

С другой стороны, если URL-адрес iframe находится в вашем домене, вы можете получить доступ к телу, но я обнаружил, что если я использую тайм-аут для удаления iframe, обратный вызов работает нормально:

// possibly excessive use of jQuery - but I've got a live working example in production
$('#myUniqueID').load(function () {
  if (typeof callback == 'function') {
    callback($('body', this.contentWindow.document).html());
  }
  setTimeout(function () {$('#frameId').remove();}, 50);
});

4
Вы можете заменить $('body', this.contentWindow.document).html()наthis.contentDocument.body.outerHTML
Сэм Соффс

12
Есть идеи, как это сделать без jQuery?
devios1

6
По состоянию на jQuery 3.0, loadушел. Пожалуйста, используйте .on('load', function() { ... })вместо этого.
Двойник

36

Я использую jQuery, и на удивление это похоже на загрузку, так как я только что протестировал и загрузил тяжелую страницу, и я не получал предупреждение в течение нескольких секунд, пока не увидел загрузку iframe:

$('#the_iframe').load(function(){
    alert('loaded!');
});

Поэтому, если вы не хотите использовать jQuery, взгляните на их исходный код и посмотрите, не ведет ли себя эта функция по-разному с элементами iframe DOM, я сам посмотрю на нее позже, когда мне будет интересно, и опубликую здесь. Также я тестировал только на последнем хроме.


Я заметил, что вы создали элемент DOM с чистым javascript, а затем передали эту переменную в jQuery в качестве селектора, может быть, поэтому ваш код не работает?
Нео

12
По состоянию на jQuery 3.0, loadушел. Пожалуйста, используйте .on('load', function() { ... })вместо этого.
Двойник

8

Внутренний HTML-код вашего iframe пуст, поскольку ваш тег iframe не окружает содержимое родительского документа. Чтобы получить содержимое со страницы, на которую ссылается атрибут src iframe, вам необходимо получить доступ к свойству iframe contentDocument. Исключение будет выдано, если src из другого домена. Это функция безопасности, которая предотвращает выполнение произвольного JavaScript на чужой странице, что может привести к уязвимости межсайтового скриптинга. Вот пример кода, иллюстрирующий то, о чем я говорю:

<script src="http://prototypejs.org/assets/2009/8/31/prototype.js" type="text/javascript"></script>

<h1>Parent</h1>

<script type="text/javascript">
function on_load(iframe) {
  try {
    // Displays the first 50 chars in the innerHTML of the
    // body of the page that the iframe is showing.
    // EDIT 2012-04-17: for wider support, fallback to contentWindow.document
    var doc = iframe.contentDocument || iframe.contentWindow.document;
    alert(doc.body.innerHTML.substring(0, 50));
  } catch (e) {
    // This can happen if the src of the iframe is
    // on another domain
    alert('exception: ' + e);
  }
}
</script>
<iframe id="child" src="iframe_content.html" onload="on_load(this)"></iframe>

Чтобы продолжить пример, попробуйте использовать это в качестве содержимого iframe:

<h1>Child</h1>

<a href="http://www.google.com/">Google</a>

<p>Use the preceeding link to change the src of the iframe
to see what happens when the src domain is different from
that of the parent page</p>

1
Свойство contentDocument не поддерживается IE 7, а может быть, и больше IE, способ работы с IE - это window ['iframeid']. document или точно такой же window.frames ['iframeid']. документ, подтверждающий ссылку здесь, разработчик. mozilla.org/en/…
Ольга

7

Мне приходилось делать это в тех случаях, когда такие документы, как word docs и pdfs, передавались в iframe и находили решение, которое работает довольно хорошо. Ключ обрабатывает onreadystatechangedсобытие в iframe.

Допустим, имя вашего фрейма "myIframe". Сначала где-то в вашем коде запуска (я делаю это в любом месте после iframe) добавить что-то вроде этого, чтобы зарегистрировать обработчик событий:

document.getElementById('myIframe').onreadystatechange = MyIframeReadyStateChanged;

Я не смог использовать атрибут onreadystatechage в iframe, я не могу вспомнить почему, но приложение должно было работать в IE 7 и Safari 3, так что это может быть фактором.

Вот пример того, как получить полное состояние:

function MyIframeReadyStateChanged()
{
    if(document.getElementById('myIframe').readyState == 'complete')
    {
        // Do your complete stuff here.
    }
}

6

Я хотел скрыть ожидающий div, когда содержимое i-кадра полностью загружено в IE, я пробовал буквально все решения, упомянутые в Stackoverflow.Com, но ничего не получалось, как я хотел.

Тогда у меня появилась идея, что когда содержимое i-кадра полностью загружено, событие загрузки $ (Window) может быть запущено. И это именно то, что случилось. Итак, я написал этот небольшой сценарий и работал как по волшебству:

     $(window).load(function () {
     //alert("Done window ready ");
     var lblWait = document.getElementById("lblWait");
     if (lblWait != null ) {
         lblWait.style.visibility = "false";
         document.getElementById("divWait").style.display = "none";
     }
 });

Надеюсь это поможет.


Это простое решение, и оно отлично работает, если вы хотите, чтобы ваш javascript выполнялся ПОСЛЕ полной загрузки страницы. это означает, что сначала вы видите полностью загруженную страницу без эффекта js, а через секунду или две (в зависимости от нагрузки) произойдут любые изменения, созданные javascript. Я лично пытался изменить размер своего iframe, и это работает, если вы не обращаете внимания на экран в течение первых трех секунд после нажатия на страницу, но в противном случае это может (как и в моем случае) выглядеть как пэчворк для кода.
амперсанды

1
спасибо за ваш комментарий, это решение отлично работало в моем случае, так как я хотел, чтобы iframe загружался после загрузки страницы.
Нада Н. Хантули

2

У меня была такая же проблема, как и у вас. Что я сделал, так это то, что я использую что-то под названием jQuery. То, что вы затем делаете в коде JavaScript, это:

$(function(){ //this is regular jQuery code. It waits for the dom to load fully the first time you open the page.

    $("#myIframeId").load(function(){
       callback($("#myIframeId").html());
       $("#myIframeId").remove();

    });

});

Кажется, когда вы удаляете свой iFrame, прежде чем взять HTML из него. Теперь я вижу проблему с этим: р

Надеюсь это поможет :).


1

У меня есть похожий код в моих проектах, который отлично работает. Адаптируя мой код к вашей функции, решение может быть следующим:

function xssRequest(url, callback)
{
    var iFrameObj = document.createElement('IFRAME');
    iFrameObj.id = 'myUniqueID';
    document.body.appendChild(iFrameObj);       
    iFrameObj.src = url;                        

    $(iFrameObj).load(function() 
    {
        callback(window['myUniqueID'].document.body.innerHTML);
        document.body.removeChild(iFrameObj);
    });
}

Возможно, у вас есть пустой innerHTML, потому что (одна или обе причины): 1. вы должны использовать его против элемента body 2. вы удалили iframe из DOM вашей страницы


1

Я думаю, что событие загрузки правильно. Неправильно то, что вы используете для извлечения контента из iframe контента dom.

Что вам нужно, это HTML-код страницы, загруженной в iframe, а не HTML-код объекта iframe.

Что вам нужно сделать, это получить доступ к содержанию документа с iFrameObj.contentDocument. Это возвращает доменное имя страницы, загруженной в iframe, если она находится в том же домене текущей страницы.

Я хотел бы получить содержимое, прежде чем удалить iframe.

Я тестировал в Firefox и Opera.

Тогда я думаю, что вы можете получить свои данные с помощью $(childDom).html()или$(childDom).find('some selector') ...


0

У меня была точно такая же проблема в прошлом, и единственный способ найти ее - это добавить обратный вызов на страницу iframe. Конечно, это работает только тогда, когда у вас есть контроль над содержанием iframe.


22
Я не голосовал против вас, но я полагаю, что вы были отклонены, потому что вы предложили именно то, что он сказал, что он не может сделать - он действительно сказал: «Я не контролирую контент в IFRAME, поэтому я могу» отзовите обратный звонок оттуда.
Дэйв Хейнс

-1

Использование onloadattrbute решит вашу проблему.

Вот пример.

function a() {
alert("Your iframe has been loaded");
}
<iframe src="https://stackoverflow.com" onload="a()"></iframe>

Это то, что вы хотите?

Нажмите здесь для получения дополнительной информации.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.