Callback Javascript saat IFRAME selesai memuat?


147

Saya perlu melakukan panggilan balik ketika IFRAME telah selesai memuat. Saya tidak punya kendali atas konten di IFRAME, jadi saya tidak bisa memecat panggilan balik dari sana.

IFRAME ini dibuat secara terprogram, dan saya perlu meneruskan datanya sebagai variabel dalam panggilan balik, serta memusnahkan iframe.

Ada ide?

EDIT:

Inilah yang saya miliki sekarang:

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

Panggilan balik ini sebelum iFrame dimuat, sehingga panggilan balik tidak memiliki data yang dikembalikan.


1
Saya pikir Anda tidak ingin melampirkan pengendali acara di iframe itu sendiri tetapi itu jendela konten.
bobwienholt

1
Masalahnya adalah permintaan lintas-domain. Anda tidak dapat melakukannya jika iframe berasal dari domain lain
Victor

Sebenarnya, ada acara pemuatan di objek iframe yang menyala setiap kali iframe selesai memuat dokumen, jika tidak, Anda harus terhubung ke jendela setelah setiap pemuatan
Juan Mendes


Lihat jawaban saya di sini: stackoverflow.com/a/36155560/3894981
Bung

Jawaban:


49

Pertama, menggunakan nama fungsi xssRequest , sepertinya Anda mencoba permintaan lintas situs - yang jika benar, Anda tidak akan dapat membaca konten iframe.

Di sisi lain, jika URL iframe ada di domain Anda, Anda dapat mengakses isi, tetapi saya menemukan bahwa jika saya menggunakan batas waktu untuk menghapus iframe, callback berfungsi dengan baik:

// 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
Anda bisa menggantinya $('body', this.contentWindow.document).html()denganthis.contentDocument.body.outerHTML
Sam Soffes

12
Adakah yang tahu bagaimana melakukan ini tanpa jQuery?
devios1

6
Pada jQuery 3.0, loadhilang. Silakan gunakan .on('load', function() { ... })sebagai gantinya.
Doppelganger

36

Saya menggunakan jQuery dan anehnya ini tampaknya memuat karena saya baru saja menguji dan memuat halaman yang berat dan saya tidak mendapatkan peringatan selama beberapa detik sampai saya melihat beban iframe:

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

Jadi, jika Anda tidak ingin menggunakan jQuery, lihat kode sumbernya dan lihat apakah fungsi ini berbeda dengan elemen iframe DOM, saya akan melihatnya sendiri nanti karena saya tertarik dan memposting di sini. Juga saya hanya menguji di chrome terbaru.


Saya perhatikan Anda membuat elemen DOM dengan javascript murni dan kemudian meneruskan variabel itu ke jQuery sebagai pemilih, mungkin itu sebabnya kode Anda tidak berfungsi?
Neo

12
Pada jQuery 3.0, loadhilang. Silakan gunakan .on('load', function() { ... })sebagai gantinya.
Doppelganger

8

InnerHTML iframe Anda kosong karena tag iframe Anda tidak mengelilingi konten apa pun di dokumen induk. Untuk mendapatkan konten dari halaman yang dirujuk oleh atribut src iframe, Anda perlu mengakses properti contentDocument iframe. Pengecualian akan dilemparkan jika src berasal dari domain yang berbeda. Ini adalah fitur keamanan yang mencegah Anda mengeksekusi JavaScript sewenang-wenang pada halaman orang lain, yang akan membuat kerentanan skrip lintas situs. Berikut adalah beberapa contoh kode yang menggambarkan apa yang saya bicarakan:

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

Untuk melanjutkan contoh, coba gunakan ini sebagai konten 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
properti contentDocument tidak didukung oleh IE 7 dan mungkin lebih banyak IE juga, cara untuk berurusan dengan IE adalah window ['iframeid'] .document atau apa itu window.frame yang persis sama . mozilla.org/en/…
Olga

7

Saya harus melakukan ini dalam kasus di mana dokumen seperti word docs dan pdf sedang di-stream ke iframe dan menemukan solusi yang berfungsi cukup baik. Kuncinya adalah menangani onreadystatechangedacara di iframe.

Katakanlah nama frame Anda adalah "myIframe". Pertama di suatu tempat di startup kode Anda (saya melakukannya sebaris di mana saja setelah iframe) tambahkan sesuatu seperti ini untuk mendaftarkan event handler:

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

Saya tidak dapat menggunakan atribut onreadystatechage pada iframe, saya tidak ingat mengapa, tetapi aplikasi harus bekerja di IE 7 dan Safari 3, sehingga mungkin menjadi faktor.

Berikut adalah contoh cara mendapatkan status lengkap:

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

6

Saya ingin menyembunyikan div spinner yang menunggu ketika konten frame saya dimuat penuh pada IE, saya mencoba setiap solusi yang disebutkan dalam Stackoverflow.Com, tetapi dengan tidak ada yang berfungsi seperti yang saya inginkan.

Lalu saya punya ide, bahwa ketika konten bingkai saya dimuat penuh, peristiwa memuat $ (Jendela) mungkin dipecat. Dan itulah yang terjadi. Jadi, saya menulis skrip kecil ini, dan bekerja seperti sulap:

     $(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";
     }
 });

Semoga ini membantu.


ini adalah solusi sederhana dan berfungsi dengan baik jika Anda ingin javascript Anda dieksekusi SETELAH seluruh halaman dimuat. ini berarti bahwa pertama Anda melihat halaman yang dimuat penuh, tanpa efek js, dan setelah mungkin satu atau dua detik (tergantung pada beban) perubahan apa pun yang dibuat oleh javascript akan terjadi kemudian. Saya pribadi mencoba mengubah ukuran iframe saya, dan itu berfungsi jika Anda tidak memperhatikan layar selama tiga detik pertama setelah mengklik pada halaman tetapi yang lain ini mungkin (seperti dalam kasus saya) muncul sebagai tambalan ke kode.
ampersands

1
terima kasih atas komentar Anda, solusi ini bekerja sangat baik untuk kasus saya, karena saya ingin iframe dimuat setelah halaman dimuat.
Nada N. Hantouli

2

Saya memiliki masalah yang sama seperti Anda. Apa yang saya lakukan adalah saya menggunakan sesuatu yang disebut jQuery. Apa yang kemudian Anda lakukan dalam kode javascript adalah ini:

$(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();

    });

});

Tampaknya saat Anda menghapus iFrame sebelum Anda mengambil html darinya. Sekarang, saya melihat masalah dengan itu: p

Semoga ini membantu :).


1

Saya memiliki kode serupa di proyek saya yang berfungsi dengan baik. Mengadaptasi kode saya ke fungsi Anda, solusinya bisa sebagai berikut:

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

Mungkin Anda memiliki innerHTML kosong karena (satu atau kedua penyebab): 1. Anda harus menggunakannya terhadap elemen tubuh 2. Anda telah menghapus iframe dari halaman DOM


1

Saya pikir acara muat benar. Apa yang tidak benar adalah cara yang Anda gunakan untuk mengambil kembali konten dari konten iframe dom.

Yang Anda butuhkan adalah html dari halaman yang dimuat di iframe bukan html dari objek iframe.

Yang harus Anda lakukan adalah mengakses dokumen konten iFrameObj.contentDocument. Ini mengembalikan dom halaman yang dimuat di dalam iframe, jika berada pada domain yang sama dengan halaman saat ini.

Saya akan mengambil kembali konten sebelum menghapus iframe.

Saya sudah menguji di firefox dan opera.

Maka saya pikir Anda dapat mengambil kembali data Anda dengan $(childDom).html()atau$(childDom).find('some selector') ...


0

Saya memiliki masalah yang sama persis di masa lalu dan satu-satunya cara saya menemukannya untuk memperbaikinya adalah dengan menambahkan callback ke halaman iframe. Tentu saja itu hanya berfungsi ketika Anda memiliki kendali atas konten iframe.


22
Saya tidak memilih Anda, tetapi saya kira Anda ditolak karena Anda menyarankan dengan tepat apa yang dia katakan tidak bisa dia lakukan - dia memang mengatakan secara spesifik, "Saya tidak punya kendali atas konten di IFRAME, jadi saya bisa ' t memecat callback dari sana. "
Dave Haynes

-1

Menggunakan onloadattrbute akan menyelesaikan masalah Anda.

Berikut ini sebuah contoh.

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

Apa ini yang kau inginkan?

Klik di sini untuk informasi lebih lanjut.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.