Відкликання 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 з іншого домену
Victor

Насправді, на об'єкт iframe відбувається подія завантаження, яка спрацьовує кожного разу, якщо iframe закінчує завантаження документа, інакше вам потрібно буде підключитися до вікна після кожного завантаження
Juan Mendes


Дивіться мою відповідь тут: 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() { ... })замість цього.
Doppelganger

36

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

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

Отже, якщо ви не хочете використовувати jQuery, подивіться на їх вихідний код і побачите, чи поводиться ця функція по-різному з елементами DOM iframe, я перегляну її на себе пізніше, як мені це цікаво, і опублікуйте тут. Також я протестував лише на останньому хромі.


Я помітив, що ви створили елемент DOM з чистим JavaScript, а потім передали цю змінну jQuery як селектор, можливо, тому код не працює?
Нео

12
Станом на jQuery 3.0, loadйого немає. Будь ласка, використовуйте .on('load', function() { ... })замість цього.
Doppelganger

8

Внутрішня HTMLML вашого 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 - це вікно ['iframeid'] . mozilla.org/uk/…
Ольга

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 з нього. Тепер я бачу проблему з цим: p

Сподіваюся, це допомагає :).


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

Можливо, у вас порожній внутрішній HTML-код, оскільки (одна чи обидві причини): 1. ви повинні використовувати його проти елемента body 2. ви видалили iframe зі своєї сторінки DOM


1

Я думаю, що подія навантаження правильна. Неправильно - це спосіб, який ви використовуєте для відтворення контенту з iframe content dom.

Вам потрібен html сторінки, завантаженої в iframe, а не html об’єкта iframe.

Що вам потрібно зробити, це отримати доступ до документа зі змістом iFrameObj.contentDocument. Це повертає домен сторінки, завантаженої всередині iframe, якщо вона знаходиться на тому самому домені поточної сторінки.

Я б відновив вміст перед тим, як видалити iframe.

Я випробував фаєрфокс та оперу.

Тоді я думаю, ви можете отримати свої дані за допомогою $(childDom).html()або$(childDom).find('some selector') ...


0

У мене була та сама проблема в минулому, і єдиний спосіб, який я вирішив це виправити, - це додавання зворотного дзвінка на сторінку iframe. Звичайно, це працює лише тоді, коли ви маєте контроль над вмістом iframe.


22
Я не проголосував за вас, але я думаю, що ви проголосували, тому що ви запропонували саме те, що він сказав, що він не може робити - він сказав конкретно: "Я не маю контролю над вмістом в IFRAME, тому я можу" t відправте зворотний дзвінок звідти. "
Дейв Хейнес

-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.