Обратный вызов 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.