Detectando quando o conteúdo Iframe foi carregado (navegador cruzado)

90

Estou tentando detectar quando um iframe e seu conteúdo foram carregados, mas não estou tendo muita sorte. Meu aplicativo recebe alguma entrada em campos de texto na janela principal e atualiza o iframe para fornecer uma 'visualização ao vivo'

Comecei com o seguinte código (YUI) para detectar quando ocorre o evento de carregamento do iframe.

$E.on('preview-pane', 'load', function(){
    previewBody = $('preview-pane').contentWindow.document.getElementsByTagName('body')[0];
}

'painel de visualização' é o ID do meu iframe e estou usando YUI para anexar o manipulador de eventos. No entanto, a tentativa de acessar o corpo em meu retorno de chamada (ao carregar o iframe) falha, acho que porque o iframe carrega antes que o manipulador de eventos esteja pronto. Este código funciona se eu atrasar o carregamento do iframe, fazendo o script php que o gera dormir.

Basicamente, estou perguntando qual é a abordagem correta entre navegadores para detectar quando o iframe foi carregado e seu documento está pronto.

David Snabel-Caunt
fonte
1
Começar com YUI é uma má ideia (assim como qualquer outra biblioteca JS). Por quê? Porque você simplesmente não pode saber que mágica aquela biblioteca está fazendo. Se eles não suportarem "load" totalmente, é melhor você mesmo fazer isso em um javascript claro e legível.
Christian
2
Você pode frequentemente ler o código-fonte da biblioteca @Christian. Acho que isso geralmente dá ótimas dicas sobre como fazer você mesmo, independentemente de você usar a implementação ou não.
AJP
@AJP Você entendeu mal meu ponto. Se você estiver fazendo algo do qual não tem certeza, é melhor ter menos código para que haja menos espaço para erros.
Christian
2
Depende de como você olha para isso. Eu sabia que o tratamento de eventos da YUI funcionava na época, então não precisei me preocupar com essa parte do código. Eu também sabia como escrever meu próprio manipulador addEvent, não que funcionasse melhor do que o YUI com relação a esse problema.
David Snabel-Caunt
1
@Nico A questão se refere a YUI e $ é um alias para o wrapper Dom de YUI.
David Snabel-Caunt

Respostas:

73

detectar quando o iframe foi carregado e seu documento está pronto?

É ideal se você puder fazer com que o iframe se identifique a partir de um script dentro do frame. Por exemplo, ele poderia chamar uma função pai diretamente para dizer que está pronto. É sempre necessário cuidado com a execução de código cross-frame, pois as coisas podem acontecer em uma ordem inesperada. Outra alternativa é definir 'var isready = true;' em seu próprio escopo e fazer com que o script pai detecte 'contentWindow.isready' (e adicione o manipulador onload se não).

Se por algum motivo não for prático ter o documento iframe cooperando, você tem o problema tradicional de corrida de carga, ou seja, mesmo que os elementos estejam próximos um do outro:

<img id="x" ... />
<script type="text/javascript">
    document.getElementById('x').onload= function() {
        ...
    };
</script>

não há garantia de que o item ainda não tenha sido carregado no momento em que o script for executado.

As maneiras de sair das corridas de carga são:

  1. no IE, você pode usar a propriedade 'readyState' para ver se algo já está carregado;

  2. se ter o item disponível apenas com JavaScript habilitado for aceitável, você pode criá-lo dinamicamente, definindo a função de evento 'onload' antes de definir a origem e anexar à página. Nesse caso, ele não pode ser carregado antes que o retorno de chamada seja definido;

  3. a maneira tradicional de incluí-lo na marcação:

    <img onload="callback(this)" ... />

Manipuladores 'onsomething' embutidos em HTML são quase sempre a coisa errada e devem ser evitados, mas neste caso às vezes é a opção menos ruim.

bobince
fonte
Obrigado. Minha solução verifica o readyState (se existir) e, em seguida, o comprimento do innerHTML dos elementos do corpo para ver se ele foi carregado. Caso contrário, anexa o manipulador de eventos de carregamento. Parece funcionar bem
David Snabel-Caunt,
8
-1 - eventos inline não são "ruins", isso é apenas a moda atual. Na verdade, eventos inline são mais fáceis de depurar e entender, ao contrário de seus equivalentes mágicos (que, por outro lado, são mais fáceis de anexar, empilhar e usar perfeitamente).
Christian
1
@Christian, eventos inline também são a melhor opção quando você precisa anexar um evento a cada elemento de uma lista muito longa. Como você já está em loop para construir a lista no lado do servidor, é muito mais eficiente anexar o evento embutido também.
haknick
16
@haknick Você não gostaria de usar um único ouvinte de evento na lista e usar um delegado de evento? Isso seria mais eficiente.
David Snabel-Caunt
4
Isso não funcionaria se o iframe fosse entre domínios. O script dentro do iframe não pode acessar a janela pai.
Sudheer Someshwara
48

Veja esta postagem do blog. Ele usa jQuery, mas deve ajudá-lo mesmo se você não estiver usando.

Basicamente, você adiciona isso ao seu document.ready()

$('iframe').load(function() {
    RunAfterIFrameLoaded();
});
kgiannakakis
fonte
Interessante, mas o problema que tenho é com os eventos de carregamento e o tempo. Estou aguardando o evento de carregamento conforme recomendado por esse artigo.
David Snabel-Caunt,
eu tentei isso com console.log. ele é registrado depois que o iframe é carregado.
shoreif2000
12

Para aqueles que usam React, detectar um evento de carregamento de iframe de mesma origem é tão simples quanto definir o onLoadouvinte de evento no elemento iframe.

<iframe src={'path-to-iframe-source'} onLoad={this.loadListener} frameBorder={0} />

Farzad YZ
fonte
O onLoadevento só pode ser disparado para iframe de mesma origem?
L_K
2

Para qualquer pessoa que use o Ember, isso deve funcionar conforme o esperado:

<iframe onLoad={{action 'actionName'}}  frameborder='0' src={{iframeSrc}} />
Max Wallace
fonte