Détection du chargement du contenu Iframe (Cross browser)

90

J'essaie de détecter quand une iframe et son contenu se sont chargés mais je n'ai pas beaucoup de chance. Mon application prend certaines entrées dans les champs de texte de la fenêtre parent et met à jour l'iframe pour fournir un `` aperçu en direct ''

J'ai commencé avec le code suivant (YUI) pour détecter quand l'événement de chargement iframe se produit.

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

'preview-pane' est l'ID de mon iframe et j'utilise YUI pour attacher le gestionnaire d'événements. Cependant, essayer d'accéder au corps de mon rappel (lors du chargement de l'iframe) échoue, je pense que l'iframe se charge avant que le gestionnaire d'événements ne soit prêt. Ce code fonctionne si je retarde le chargement de l'iframe en mettant en veille le script php qui le génère.

Fondamentalement, je demande quelle est la bonne approche dans les navigateurs pour détecter quand l'iframe est chargé et que son document est prêt?

David Snabel-Caunt
la source
1
Commencer avec YUI est une mauvaise idée (ainsi que toute autre bibliothèque JS). Pourquoi? Parce que vous ne pouvez pas savoir quelle magie cette bibliothèque fait. S'ils ne supportent pas complètement le "chargement", vous feriez mieux de le faire vous-même en javascript clair et lisible.
Christian
2
Vous pouvez souvent lire le code source de la bibliothèque @Christian. Je trouve que cela vous donne généralement de bons conseils sur la façon de le faire vous-même, que vous utilisiez ensuite leur mise en œuvre ou non.
AJP
@AJP Vous avez mal compris mon point. Si vous faites quelque chose dont vous n'êtes pas sûr, il est préférable d'avoir moins de code pour qu'il y ait moins de place pour les erreurs.
Christian
2
Cela dépend de la façon dont vous le regardez. Je savais que la gestion des événements de YUI fonctionnait à l'époque, donc je n'avais pas à m'inquiéter de cette partie du code. Je savais aussi comment écrire mon propre gestionnaire addEvent, non pas que cela fonctionnait mieux que YUI en ce qui concerne ce problème.
David Snabel-Caunt
1
@Nico La question fait référence à YUI et $ est un alias du wrapper Dom de YUI.
David Snabel-Caunt le

Réponses:

73

détecter quand l'iframe s'est chargé et que son document est prêt?

C'est idéal si vous pouvez faire en sorte que l'iframe vous dise à partir d'un script à l'intérieur du cadre. Par exemple, il pourrait appeler une fonction parent directement pour lui dire qu'elle est prête. Il faut toujours faire attention lors de l'exécution de code inter-cadres, car les choses peuvent se produire dans un ordre auquel vous ne vous attendez pas. Une autre alternative est de définir 'var isready = true;' dans sa propre portée, et faites renifler le script parent pour 'contentWindow.isready' (et ajoutez le gestionnaire onload si ce n'est pas le cas).

Si, pour une raison quelconque, il n'est pas pratique de faire coopérer le document iframe, vous avez le problème traditionnel de la course à la charge, à savoir que même si les éléments sont les uns à côté des autres:

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

il n'y a aucune garantie que l'élément ne sera pas déjà chargé au moment où le script s'exécute.

Les moyens de sortir des courses de charge sont:

  1. sur IE, vous pouvez utiliser la propriété 'readyState' pour voir si quelque chose est déjà chargé;

  2. si avoir l'élément disponible uniquement avec JavaScript activé est acceptable, vous pouvez le créer dynamiquement, en définissant la fonction d'événement 'onload' avant de définir la source et de l'ajouter à la page. Dans ce cas, il ne peut pas être chargé avant que le rappel ne soit défini;

  3. la façon traditionnelle de l'inclure dans le balisage:

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

Les gestionnaires "onsomething" en ligne en HTML sont presque toujours la mauvaise chose et à éviter, mais dans ce cas, c'est parfois la moins mauvaise option.

bobince
la source
Merci. Ma solution vérifie le readyState (s'il existe), puis la longueur des éléments de corps innerHTML pour voir si elle a été chargée. Sinon, attache le gestionnaire d'événements de chargement. Semble fonctionner bien
David Snabel-Caunt
8
-1 - les événements en ligne ne sont pas "mauvais", c'est juste la mode actuelle. En fait, les événements en ligne sont plus faciles à déboguer et à comprendre, contrairement à leurs homologues magiques (qui, en revanche, sont plus faciles à attacher, à empiler et à utiliser de manière transparente).
Christian
1
@Christian, les événements en ligne sont également la meilleure option lorsque vous devez attacher un événement à chaque élément d'une très longue liste. Comme vous êtes déjà en train de créer la liste côté serveur, il est beaucoup plus efficace d'attacher également l'événement en ligne.
haknick
16
@haknick Ne voudriez-vous pas utiliser un seul écouteur d'événement sur la liste et utiliser un délégué d'événement? Ce serait plus efficace.
David Snabel-Caunt
4
Cela ne fonctionnerait pas si l'iframe est interdomaine. Le script dans iframe ne peut pas accéder à la fenêtre parent.
Sudheer Someshwara
48

Voir ce billet de blog. Il utilise jQuery, mais cela devrait vous aider même si vous ne l'utilisez pas.

En gros, vous ajoutez ceci à votre document.ready()

$('iframe').load(function() {
    RunAfterIFrameLoaded();
});
kgiannakakis
la source
Intéressant, mais le problème que j'ai est avec les événements de charge et le timing. J'écoute l'événement de chargement comme conseillé par cet article.
David Snabel-Caunt
j'ai essayé ceci avec console.log. il est enregistré après le chargement de l'iframe.
shorif2000
12

Pour ceux qui utilisent React, la détection d'un événement de chargement iframe de même origine est aussi simple que de définir onLoadun écouteur d'événement sur l'élément iframe.

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

Farzad YZ
la source
L' onLoadévénement ne peut-il se déclencher que pour une iframe de même origine?
L_K
2

Pour toute personne utilisant Ember, cela devrait fonctionner comme prévu:

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