Gọi lại Javascript khi IFRAME tải xong?


147

Tôi cần thực hiện một cuộc gọi lại khi IFRAME đã tải xong. Tôi không có quyền kiểm soát nội dung trong IFRAME, vì vậy tôi không thể thực hiện cuộc gọi lại từ đó.

IFRAME này được tạo lập trình và tôi cần truyền dữ liệu của nó dưới dạng một biến trong cuộc gọi lại, cũng như phá hủy iframe.

Có ý kiến ​​gì không?

BIÊN TẬP:

Đây là những gì tôi có bây giờ:

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

Cuộc gọi lại này trước khi iFrame được tải, vì vậy cuộc gọi lại không có dữ liệu nào được trả về.


1
Tôi nghĩ rằng bạn không muốn đính kèm trình xử lý sự kiện trên iframe nhưng đó là cửa sổ nội dung.
bobwienholt

1
Vấn đề là yêu cầu tên miền chéo. Bạn không thể làm điều đó nếu iframe đến từ một tên miền khác
Victor

Trên thực tế, có một sự kiện tải trên đối tượng iframe kích hoạt mỗi khi iframe kết thúc việc tải tài liệu, nếu không, bạn cần phải nối vào cửa sổ sau mỗi lần tải
Juan Mendes


Xem câu trả lời của tôi ở đây: stackoverflow.com/a/36155560/3894981
anh chàng

Câu trả lời:


49

Trước tiên, với tên hàm xssRequest , có vẻ như bạn đang thử yêu cầu trang chéo - nếu điều đó đúng, bạn sẽ không thể đọc nội dung của iframe.

Mặt khác, nếu URL của iframe nằm trên miền của bạn, bạn có thể truy cập vào phần thân, nhưng tôi thấy rằng nếu tôi sử dụng thời gian chờ để loại bỏ iframe thì cuộc gọi lại hoạt động tốt:

// 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
bạn có thể thay thế $('body', this.contentWindow.document).html()bằngthis.contentDocument.body.outerHTML
Sam Soffes

12
Bất kỳ ý tưởng làm thế nào để làm điều này mà không cần jQuery?
devios1

6
Kể từ jQuery 3.0, loadđã biến mất. Vui lòng sử dụng .on('load', function() { ... })thay thế.
Doppelganger

36

Tôi đang sử dụng jQuery và điều đáng ngạc nhiên là nó dường như tải khi tôi vừa kiểm tra và tải một trang nặng và tôi đã không nhận được cảnh báo trong vài giây cho đến khi tôi thấy tải iframe:

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

Vì vậy, nếu bạn không muốn sử dụng jQuery, hãy xem mã nguồn của họ và xem hàm này có hoạt động khác với các phần tử DOM của iframe không, tôi sẽ xem xét nó sau khi tôi quan tâm và đăng ở đây. Ngoài ra tôi chỉ thử nghiệm trong chrome mới nhất.


Tôi nhận thấy bạn đã tạo phần tử DOM bằng javascript thuần túy và sau đó chuyển biến đó sang jQuery làm công cụ chọn, có thể đó là lý do tại sao mã của bạn không hoạt động?
Neo

12
Kể từ jQuery 3.0, loadđã biến mất. Vui lòng sử dụng .on('load', function() { ... })thay thế.
Doppelganger

8

InternalHTML của iframe của bạn trống vì thẻ iframe của bạn không bao quanh bất kỳ nội dung nào trong tài liệu gốc. Để lấy nội dung từ trang được gọi bởi thuộc tính src của iframe, bạn cần truy cập vào thuộc tính contentDocument của iframe. Một ngoại lệ sẽ được ném nếu src đến từ một miền khác. Đây là một tính năng bảo mật ngăn bạn thực thi JavaScript tùy ý trên trang của người khác, điều này sẽ tạo ra lỗ hổng kịch bản chéo trang. Dưới đây là một số ví dụ mã minh họa những gì tôi đang nói về:

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

Để biết thêm ví dụ, hãy thử sử dụng nội dung này làm nội dung của 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
Thuộc tính contentDocument không được IE 7 hỗ trợ và có thể nhiều IE cũng vậy, cách đối phó với IE là cửa sổ ['iframeid']. tài liệu hoặc chính xác là cùng một window.frames ['iframeid'] . mozilla.org/vi/ Kẻ
Olga

7

Tôi đã phải làm điều này trong trường hợp các tài liệu như tài liệu word và pdf được truyền đến iframe và tìm thấy một giải pháp hoạt động khá tốt. Chìa khóa đang xử lý onreadystatechangedsự kiện trên iframe.

Hãy nói tên khung của bạn là "myIframe". Đầu tiên ở đâu đó trong quá trình khởi động mã của bạn (tôi thực hiện nội tuyến bất kỳ nơi nào sau iframe) thêm một cái gì đó như thế này để đăng ký xử lý sự kiện:

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

Tôi không thể sử dụng thuộc tính onreadystatechage trên iframe, tôi không thể nhớ tại sao, nhưng ứng dụng phải hoạt động trong IE 7 và Safari 3, vì vậy đó có thể là một yếu tố.

Dưới đây là một ví dụ về cách lấy trạng thái hoàn chỉnh:

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

6

Tôi muốn ẩn div spinner chờ khi nội dung khung i được tải đầy đủ trên IE, tôi đã thử mọi giải pháp được đề cập trong Stackoverflow.Com, nhưng không có gì hoạt động như tôi muốn.

Sau đó, tôi đã có một ý tưởng, khi nội dung khung i được tải đầy đủ, sự kiện tải $ (Window) có thể được kích hoạt. Và đó chính xác là những gì đã xảy ra. Vì vậy, tôi đã viết kịch bản nhỏ này và làm việc như ma thuật:

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

Hi vọng điêu nay co ich.


đây là một giải pháp đơn giản và hoạt động tốt nếu bạn muốn javascript của mình được thực thi SAU toàn bộ trang được tải. điều này có nghĩa là trước tiên bạn thấy trang được tải đầy đủ, không có hiệu ứng js và sau có thể một hoặc hai giây (tùy thuộc vào tải), bất kỳ thay đổi nào được tạo bởi javascript sẽ xảy ra sau đó. Cá nhân tôi đã thử thay đổi kích thước iframe của mình và nó hoạt động nếu bạn không chú ý đến màn hình trong ba giây đầu tiên sau khi nhấp vào trang nhưng điều này có thể (như trong trường hợp của tôi) xuất hiện dưới dạng mã chắp vá.
hiệu

1
cảm ơn bạn đã bình luận, giải pháp này đã hoạt động rất tốt trong trường hợp của tôi, vì tôi muốn iframe được tải sau khi trang được tải.
Nada N. Hantouli

2

Tôi đã có một vấn đề tương tự như bạn. Những gì tôi đã làm là tôi sử dụng một cái gì đó gọi là jQuery. Những gì bạn sau đó làm trong mã javascript là đây:

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

    });

});

Có vẻ như bạn xóa iFrame của bạn trước khi bạn lấy html từ nó. Bây giờ, tôi thấy một vấn đề với điều đó: p

Hi vọng điêu nay co ich :).


1

Tôi có một mã tương tự trong các dự án của tôi hoạt động tốt. Điều chỉnh mã của tôi theo chức năng của bạn, một giải pháp có thể là như sau:

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

Có thể bạn có mộtHTML bên trong trống rỗng vì (một hoặc cả hai nguyên nhân): 1. bạn nên sử dụng nó với phần tử body 2. bạn đã xóa iframe khỏi DOM trang của bạn


1

Tôi nghĩ rằng sự kiện tải là đúng. Điều không đúng là cách bạn sử dụng để truy xuất nội dung từ nội dung iframe.

Những gì bạn cần là html của trang được tải trong iframe chứ không phải html của đối tượng iframe.

Những gì bạn phải làm là truy cập tài liệu nội dung với iFrameObj.contentDocument. Điều này trả về dom của trang được tải bên trong iframe, nếu nó nằm trên cùng một miền của trang hiện tại.

Tôi sẽ truy xuất lại nội dung trước khi xóa iframe.

Tôi đã thử nghiệm trong firefox và opera.

Sau đó, tôi nghĩ rằng bạn có thể truy xuất dữ liệu của bạn với $(childDom).html()hoặc$(childDom).find('some selector') ...


0

Tôi đã có chính xác vấn đề tương tự trong quá khứ và cách duy nhất tôi tìm thấy để khắc phục nó là thêm cuộc gọi lại vào trang iframe. Tất nhiên, điều đó chỉ hoạt động khi bạn có quyền kiểm soát nội dung iframe.


22
Tôi đã không bỏ phiếu cho bạn, nhưng tôi tưởng tượng bạn đã bỏ phiếu vì bạn đề xuất chính xác những gì anh ấy nói anh ấy không thể làm - anh ấy đã nói cụ thể, "Tôi không kiểm soát nội dung trong IFRAME, vì vậy tôi có thể ' T bắn cuộc gọi lại từ đó. "
Dave Haynes

-1

Sử dụng onloadattrbute sẽ giải quyết vấn đề của bạn.

Đây là một ví dụ.

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

Đây có phải là những gì bạn muốn?

Nhấn vào đây để biết thêm thông tin.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.