Rappel Javascript lorsque IFRAME a fini de charger?

147

J'ai besoin d'exécuter un rappel lorsqu'un IFRAME a fini de se charger. Je n'ai aucun contrôle sur le contenu de l'IFRAME, je ne peux donc pas déclencher le rappel à partir de là.

Cet IFRAME est créé par programme et je dois transmettre ses données en tant que variable dans le rappel, ainsi que détruire l'iframe.

Des idées?

ÉDITER:

Voici ce que j'ai maintenant:

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

Ce rappel avant le chargement de l'iFrame, donc le rappel n'a pas de données renvoyées.

FlySwat
la source
1
Je pense que vous ne voulez pas attacher le gestionnaire d'événements sur l'iframe lui-même, mais c'est la fenêtre de contenu.
bobwienholt
1
Le problème est la demande interdomaine. Vous ne pouvez pas le faire si l'iframe provient d'un autre domaine
Victor
En fait, il y a un événement de chargement sur l'objet iframe qui se déclenche à chaque fois que l'iframe termine le chargement d'un document, sinon, vous devrez vous connecter à la fenêtre après chaque chargement
Juan Mendes
Voir ma réponse ici: stackoverflow.com/a/36155560/3894981
mec

Réponses:

49

Tout d'abord, en utilisant le nom de la fonction xssRequest, il semble que vous essayez une requête intersite - qui, si c'est vrai, vous ne pourrez pas lire le contenu de l'iframe.

D'un autre côté, si l'URL de l'iframe est sur votre domaine, vous pouvez accéder au corps, mais j'ai trouvé que si j'utilise un délai d'expiration pour supprimer l'iframe, le rappel fonctionne bien:

// 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);
});
Remy Sharp
la source
4
vous pourriez remplacer $('body', this.contentWindow.document).html()parthis.contentDocument.body.outerHTML
Sam Soffes
12
Une idée comment faire cela sans jQuery?
devios1
6
Depuis jQuery 3.0, loadest parti. Veuillez utiliser à la .on('load', function() { ... })place.
Doppelganger
36

J'utilise jQuery et, étonnamment, cela semble se charger car je viens de tester et de charger une page lourde et je n'ai pas reçu l'alerte pendant quelques secondes jusqu'à ce que je voie le chargement de l'iframe:

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

Donc, si vous ne voulez pas utiliser jQuery, jetez un œil à leur code source et voyez si cette fonction se comporte différemment avec les éléments DOM iframe, je l'examinerai moi-même plus tard car je suis intéressé et posterai ici. De plus, je n'ai testé que dans le dernier chrome.

Néo
la source
J'ai remarqué que vous avez créé l'élément DOM avec du javascript pur, puis que vous avez passé cette variable à jQuery en tant que sélecteur, c'est peut-être pourquoi votre code ne fonctionne pas?
Neo
12
Depuis jQuery 3.0, loadest parti. Veuillez utiliser à la .on('load', function() { ... })place.
Doppelganger
8

Le innerHTML de votre iframe est vide car votre balise iframe n'entoure aucun contenu dans le document parent. Afin d'obtenir le contenu de la page référencée par l'attribut src de l'iframe, vous devez accéder à la propriété contentDocument de l'iframe. Une exception sera lancée si le src provient d'un domaine différent. Il s'agit d'une fonctionnalité de sécurité qui vous empêche d'exécuter du JavaScript arbitraire sur la page de quelqu'un d'autre, ce qui créerait une vulnérabilité de script intersite. Voici un exemple de code illustrant ce dont je parle:

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

Pour approfondir l'exemple, essayez de l'utiliser comme contenu de l'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>
allyourcode
la source
1
La propriété contentDocument n'est pas prise en charge par IE 7 et peut-être plus IE aussi, la façon de traiter IE est window ['iframeid']. document ou ce qui est exactement le même window.frames ['iframeid']. lien preuve de document ici développeur. mozilla.org/en/...
Olga
7

J'ai dû faire cela dans les cas où des documents tels que des documents Word et des fichiers PDF étaient diffusés sur l'iframe et trouvaient une solution qui fonctionne plutôt bien. La clé gère l' onreadystatechangedévénement sur l'iframe.

Disons que le nom de votre cadre est "myIframe". Tout d'abord, quelque part dans votre démarrage de code (je le fais en ligne n'importe où après l'iframe), ajoutez quelque chose comme ça pour enregistrer le gestionnaire d'événements:

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

Je n'ai pas pu utiliser un attribut onreadystatechage sur l'iframe, je ne me souviens pas pourquoi, mais l'application devait fonctionner dans IE 7 et Safari 3, donc cela peut être un facteur.

Voici un exemple de comment obtenir l'état complet:

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

Je voulais cacher le div spinner en attente lorsque le contenu i frame est entièrement chargé sur IE, j'ai essayé littéralement toutes les solutions mentionnées dans Stackoverflow.Com, mais rien ne fonctionnait comme je le souhaitais.

Ensuite, j'ai eu une idée, que lorsque le contenu du cadre i est complètement chargé, l'événement de chargement $ (Window) pourrait être déclenché. Et c'est exactement ce qui s'est passé. Alors, j'ai écrit ce petit script et j'ai travaillé comme par magie:

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

J'espère que cela t'aides.

Nada N. Hantouli
la source
c'est une solution simple et fonctionne très bien si vous voulez que votre javascript soit exécuté APRÈS que la page entière soit chargée. cela signifie que vous voyez d'abord la page entièrement chargée, sans effet js, et après peut-être une seconde ou deux (selon la charge), les modifications créées par le javascript se produiront alors. J'ai personnellement essayé de redimensionner mon iframe, et cela fonctionne si vous ne faites pas attention à l'écran pendant les trois premières secondes après avoir cliqué sur une page, mais sinon cela peut (comme c'était dans mon cas) apparaître comme un patchwork au code.
esperluettes
1
merci pour votre commentaire, cette solution a très bien fonctionné dans mon cas, car je voulais que l'iframe soit chargé après le chargement de la page.
Nada N.Hantouli
2

J'ai eu un problème similaire à vous. Ce que j'ai fait, c'est que j'utilise quelque chose appelé jQuery. Voici ce que vous faites ensuite dans le code javascript:

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

    });

});

Il semble que vous supprimiez votre iFrame avant de récupérer le html. Maintenant, je vois un problème avec cela: p

J'espère que cela t'aides :).

Automatico
la source
1

J'ai un code similaire dans mes projets qui fonctionne bien. En adaptant mon code à votre fonction, une solution pourrait être la suivante:

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

Peut-être que vous avez un innerHTML vide parce que (une ou les deux causes): 1. vous devriez l'utiliser contre l'élément body 2. vous avez supprimé l'iframe du DOM de votre page

Pier Luigi
la source
1

Je pense que l'événement de chargement est juste. Ce qui ne va pas, c'est la façon dont vous récupérez le contenu de l'iframe content dom.

Ce dont vous avez besoin est le html de la page chargée dans l'iframe et non le html de l'objet iframe.

Ce que vous devez faire est d'accéder au document de contenu avec iFrameObj.contentDocument. Cela renvoie le dom de la page chargée à l'intérieur de l'iframe, s'il se trouve sur le même domaine de la page actuelle.

Je récupérerais le contenu avant de supprimer l'iframe.

J'ai testé dans Firefox et Opera.

Ensuite, je pense que vous pouvez récupérer vos données avec $(childDom).html()ou$(childDom).find('some selector') ...


la source
0

J'ai eu exactement le même problème dans le passé et le seul moyen que j'ai trouvé pour le résoudre était d'ajouter le rappel dans la page iframe. Bien sûr, cela ne fonctionne que lorsque vous contrôlez le contenu iframe.

roryf
la source
22
Je ne vous ai pas voté contre, mais j'imagine que vous avez été rejeté parce que vous avez suggéré exactement ce qu'il a dit qu'il ne pouvait pas faire - il a dit spécifiquement: "Je n'ai aucun contrôle sur le contenu de l'IFRAME, donc je peux" t déclencher le rappel à partir de là. "
Dave Haynes
-1

L'utilisation d' onloadattrbute résoudra votre problème.

Voici un exemple.

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

c'est ce que tu veux?

Cliquez ici pour plus d'informations.


la source