Retorno de chamada do Javascript quando o carregamento do IFRAME?


147

Preciso executar um retorno de chamada quando um IFRAME terminar de carregar. Não tenho controle sobre o conteúdo no IFRAME, portanto não posso acionar o retorno de chamada a partir daí.

Esse IFRAME é criado programaticamente e preciso passar seus dados como uma variável no retorno de chamada, além de destruir o iframe.

Alguma ideia?

EDITAR:

Aqui está o que eu tenho agora:

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

Esse retorno de chamada antes do carregamento do iFrame, portanto, o retorno de chamada não possui dados retornados.


1
Eu acho que você não deseja anexar o manipulador de eventos no próprio iframe, mas é uma janela de conteúdo.
bobwienholt

1
O problema é a solicitação entre domínios. Você não pode fazer isso se o iframe for de outro domínio
Victor

Na verdade, não é um evento carga sobre o objeto iframe que os incêndios Toda vez que os acabamentos iframe colocar um documento, caso contrário, você precisa ligar para a janela após cada carga
Juan Mendes


Veja minha resposta aqui: stackoverflow.com/a/36155560/3894981
cara

Respostas:


49

Primeiro, usando o nome da função xssRequest , parece que você está tentando uma solicitação entre sites - que, se estiver certo, não poderá ler o conteúdo do iframe.

Por outro lado, se o URL do iframe estiver no seu domínio, você poderá acessar o corpo, mas descobri que se eu usar um tempo limite para remover o iframe, o retorno de chamada funcionará bem:

// 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
você pode substituir $('body', this.contentWindow.document).html()porthis.contentDocument.body.outerHTML
Sam Soffes

12
Alguma idéia de como fazer isso sem o jQuery?
devios1

6
A partir do jQuery 3.0, loadse foi. Por favor, use em seu .on('load', function() { ... })lugar.
Doppelganger

36

Estou usando o jQuery e surpreendentemente isso parece carregar, pois acabei de testar e carregar uma página pesada e não recebi o alerta por alguns segundos até ver o carregamento do iframe:

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

Portanto, se você não quiser usar o jQuery, dê uma olhada no código-fonte e veja se essa função se comporta de maneira diferente com os elementos DOM do iframe. Também testei apenas no cromo mais recente.


Notei que você criou o elemento DOM com javascript puro e passou a variável para jQuery como seletor, talvez seja por isso que seu código não está funcionando?
Neo

12
A partir do jQuery 3.0, loadse foi. Por favor, use em seu .on('load', function() { ... })lugar.
Doppelganger

8

O innerHTML do seu iframe está em branco porque sua tag iframe não envolve nenhum conteúdo no documento pai. Para obter o conteúdo da página mencionada pelo atributo src do iframe, é necessário acessar a propriedade contentDocument do iframe. Uma exceção será lançada se o src for de um domínio diferente. Esse é um recurso de segurança que impede a execução de JavaScript arbitrário na página de outra pessoa, o que criaria uma vulnerabilidade de script entre sites. Aqui está um exemplo de código que ilustra o que estou falando:

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

Para aprofundar o exemplo, tente usar isso como o conteúdo do 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
A propriedade contentDocument não é suportada pelo IE 7 e talvez mais IE também, a maneira de lidar com o IE é window ['iframeid']. document ou o que é exatamente a mesma janela window.frames ['iframeid']. link à prova de documentos aqui developer. mozilla.org/pt/…
Olga

7

Eu tive que fazer isso nos casos em que documentos como documentos do Word e PDFs estavam sendo transmitidos para o iframe e encontrei uma solução que funciona muito bem. A chave está lidando com o onreadystatechangedevento no iframe.

Digamos que o nome do seu quadro seja "myIframe". Primeiro, em algum lugar da inicialização do código (eu o faço em qualquer lugar após o iframe), adicione algo assim para registrar o manipulador de eventos:

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

Não pude usar um atributo onreadystatechage no iframe, não me lembro por que, mas o aplicativo teve que funcionar no IE 7 e no Safari 3, portanto isso pode ter sido um fator.

Aqui está um exemplo de como obter o estado completo:

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

6

Eu queria ocultar a div de spinner em espera quando o conteúdo do quadro i estiver totalmente carregado no IE, tentei literalmente todas as soluções mencionadas no Stackoverflow.Com, mas com nada funcionou como eu queria.

Então tive uma ideia de que, quando o conteúdo do quadro i estiver totalmente carregado, o evento de carregamento $ (Window) poderá ser acionado. E foi exatamente o que aconteceu. Então, eu escrevi este pequeno script e funcionei como mágica:

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

Espero que isto ajude.


essa é uma solução simples e funciona bem se você deseja que seu javascript seja executado APÓS a página inteira ser carregada. isso significa que primeiro você vê a página totalmente carregada, sem o efeito js, ​​e depois de um ou dois segundos (dependendo da carga), quaisquer alterações criadas pelo javascript acontecerão. Eu, pessoalmente, tentei redimensionar meu iframe, e funcionará se você não prestar atenção na tela pelos primeiros três segundos após clicar em uma página, mas isso pode (como foi no meu caso) aparecer como uma colcha de retalhos no código.
mail # E

1
obrigado pelo seu comentário, esta solução funcionou muito bem no meu caso, já que eu queria que o iframe fosse carregado após o carregamento da página.
Nada N. Hantouli 01/09/2015

2

Eu tive um problema semelhante ao seu. O que fiz foi usar algo chamado jQuery. O que você faz no código javascript é o seguinte:

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

    });

});

Parece que você exclui o iFrame antes de pegar o html. Agora, vejo um problema com isso: p

Espero que isto ajude :).


1

Eu tenho um código semelhante em meus projetos que funciona bem. Adaptando meu código à sua função, uma solução pode ser a seguinte:

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

Talvez você tenha um innerHTML vazio porque (uma ou ambas as causas): 1. você deve usá-lo contra o elemento body 2. você removeu o iframe do DOM da sua página


1

Eu acho que o evento load está correto. O que não é certo é a maneira como você usa para recuperar o conteúdo do iframe content dom.

O que você precisa é o html da página carregada no iframe e não o html do objeto iframe.

O que você precisa fazer é acessar o documento de conteúdo iFrameObj.contentDocument. Isso retorna o domínio da página carregada dentro do iframe, se estiver no mesmo domínio da página atual.

Eu recuperaria o conteúdo antes de remover o iframe.

Eu testei no firefox e na ópera.

Então eu acho que você pode recuperar seus dados com $(childDom).html()ou$(childDom).find('some selector') ...


0

Eu tive exatamente o mesmo problema no passado e a única maneira de corrigi-lo foi adicionar o retorno de chamada na página iframe. Claro que isso só funciona quando você tem controle sobre o conteúdo do iframe.


22
Não votei contra, mas imagino que você foi votado porque sugeriu exatamente o que ele disse que ele não pode fazer - ele disse especificamente: "Não tenho controle sobre o conteúdo do IFRAME, então posso" não dispare o retorno de chamada a partir daí ".
Dave Haynes

-1

Usar onloadattrbute resolverá seu problema.

Aqui está um exemplo.

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

É isso que voce quer?

Clique aqui para mais informações.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.