Javascript callback เมื่อโหลด 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
dude

คำตอบ:


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

12
มีความคิดวิธีการทำสิ่งนี้โดยไม่ jQuery?
devios1

6
ตั้งแต่ jQuery 3.0 loadหายไป กรุณาใช้.on('load', function() { ... })แทน
Doppelganger

36

ฉันใช้ jQuery และน่าประหลาดใจที่ดูเหมือนว่าจะโหลดเมื่อฉันเพิ่งทดสอบและโหลดหน้าเว็บขนาดใหญ่และฉันไม่ได้รับการแจ้งเตือนเป็นเวลาสองสามวินาทีจนกว่าฉันจะเห็นโหลด iframe:

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

ดังนั้นหากคุณไม่ต้องการใช้ jQuery ลองดูที่ซอร์สโค้ดของพวกเขาและดูว่าฟังก์ชั่นนี้ทำงานอย่างไรกับองค์ประกอบ iframe DOM ที่แตกต่างกันฉันจะดูเองในภายหลังเพราะฉันสนใจและโพสต์ที่นี่ ฉันเพิ่งทดสอบกับโครเมียมล่าสุดเท่านั้น


ฉันสังเกตว่าคุณสร้างองค์ประกอบ DOM ด้วยจาวาสคริปต์ที่บริสุทธิ์แล้วส่งต่อตัวแปรนั้นไปที่ jQuery เป็นตัวเลือกซึ่งอาจเป็นสาเหตุที่รหัสของคุณไม่ทำงาน
Neo

12
ตั้งแต่ jQuery 3.0 loadหายไป กรุณาใช้.on('load', function() { ... })แทน
Doppelganger

8

innerHTML ของ iframe ของคุณว่างเปล่าเพราะแท็ก iframe ของคุณไม่ได้ล้อมรอบเนื้อหาใด ๆ ในเอกสารหลัก ในการรับเนื้อหาจากเพจที่อ้างถึงโดยแอ็ตทริบิวต์ src ของ iframe คุณต้องเข้าถึงคุณสมบัติ contentDocument ของ iframe ข้อยกเว้นจะถูกโยนหาก 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 property ไม่รองรับ IE 7 และอาจจะมากกว่า IE ด้วยเช่นกันวิธีจัดการกับ IE คือ window ['iframeid']. document หรืออะไรคือ window.frames เดียวกัน ['iframeid'] ลิงก์หลักฐานเอกสารนักพัฒนา
Olga

7

ฉันต้องทำเช่นนี้ในกรณีที่เอกสารเช่น word docs และ pdf ถูกสตรีมไปยัง 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).load(function () {
     //alert("Done window ready ");
     var lblWait = document.getElementById("lblWait");
     if (lblWait != null ) {
         lblWait.style.visibility = "false";
         document.getElementById("divWait").style.display = "none";
     }
 });

หวังว่านี่จะช่วยได้


นี่เป็นวิธีแก้ไขปัญหาที่ง่ายและทำงานได้ดีถ้าคุณต้องการให้จาวาสคริปต์ของคุณทำงานหลังจากที่โหลดหน้าเว็บทั้งหมดแล้ว นี่หมายความว่าครั้งแรกที่คุณเห็นหน้าเว็บที่โหลดเต็มโดยไม่มีผลกระทบ js และหลังจากนั้นอาจจะสองหรือสอง (ขึ้นอยู่กับภาระ) การเปลี่ยนแปลงใด ๆ ที่ถูกสร้างขึ้นโดยจาวาสคริปต์จะเกิดขึ้น ฉันพยายามปรับขนาด iframe ของฉันเป็นการส่วนตัวและใช้งานได้ถ้าคุณไม่ใส่ใจกับหน้าจอในช่วงสามวินาทีแรกหลังจากคลิกบนหน้าเว็บ แต่สิ่งนี้อาจเกิดขึ้นได้ (เหมือนในกรณีของฉัน) ปรากฏเป็นรหัส
เครื่องหมาย

1
ขอบคุณสำหรับความคิดเห็นของคุณโซลูชันนี้ใช้งานได้ดีในกรณีของฉันเนื่องจากฉันต้องการให้โหลด iframe หลังจากโหลดหน้าเว็บแล้ว
Nada N. Hantouli

2

ฉันมีปัญหาคล้ายกันกับคุณ สิ่งที่ฉันทำคือฉันใช้สิ่งที่เรียกว่า jQuery สิ่งที่คุณทำในรหัสจาวาสคริปต์คือ:

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

บางทีคุณอาจมี internalHTML ที่ว่างเปล่าเพราะ (หนึ่งหรือทั้งสองสาเหตุ): 1. คุณควรใช้มันกับองค์ประกอบของร่างกาย 2. คุณได้ลบ iframe ออกจาก DOM หน้าของคุณ


1

ฉันคิดว่าเหตุการณ์โหลดถูกต้อง สิ่งที่ไม่ถูกต้องคือวิธีที่คุณใช้เพื่อเรียกเนื้อหาจาก iframe content dom

สิ่งที่คุณต้องการคือ html ของเพจที่โหลดใน iframe ไม่ใช่ html ของออบเจ็กต์ iframe

iFrameObj.contentDocumentสิ่งที่คุณต้องทำคือการเข้าถึงเอกสารเนื้อหาด้วย สิ่งนี้จะส่งคืน dom ของหน้าเว็บที่โหลดภายใน iframe หากอยู่ในโดเมนเดียวกันของหน้าปัจจุบัน

ฉันจะเรียกคืนเนื้อหาก่อนที่จะลบ iframe

ฉันทดสอบใน Firefox และโอเปร่า

จากนั้นฉันคิดว่าคุณสามารถเรียกคืนข้อมูลด้วย$(childDom).html()หรือ$(childDom).find('some selector') ...


0

ฉันมีปัญหาเดียวกันในอดีตและวิธีเดียวที่ฉันพบว่าแก้ไขได้คือการเพิ่มการติดต่อกลับลงในหน้า iframe แน่นอนว่าใช้งานได้เมื่อคุณควบคุมเนื้อหา iframe เท่านั้น


22
ฉันไม่ได้ลงคะแนนคุณ แต่ฉันคิดว่าคุณได้รับการโหวตเพราะคุณแนะนำสิ่งที่เขาบอกว่าเขาไม่สามารถทำได้ - เขาพูดโดยเฉพาะ "ฉันไม่สามารถควบคุมเนื้อหาใน IFRAME ได้ดังนั้นฉันจึงสามารถ ' อย่าไล่โทรกลับจากที่นั่น "
Dave Haynes

-1

การใช้onloadattrbute จะช่วยแก้ปัญหาของคุณ

นี่คือตัวอย่าง

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

นี่คือสิ่งที่คุณต้องการ?

คลิกที่นี่สำหรับข้อมูลเพิ่มเติม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.