web-dev-qa-db-fra.com

Créer une iframe avec du HTML donné dynamiquement

J'essaie de créer un iframe à partir de JavaScript et de le remplir avec du code HTML arbitraire, comme ceci:

var html = '<body>Foo</body>';
var iframe = document.createElement('iframe');
iframe.src = 'data:text/html;charset=utf-8,' + encodeURI(html);

Je m'attendrais à ce que iframe contienne alors une fenêtre et un document valides. Cependant, ce n'est pas le cas:

> console.log (iframe.contentWindow);
nul

Essayez par vous-même: http://jsfiddle.net/TrevorBurnham/9k9Pe/

Qu'est-ce que je néglige?

113
Trevor Burnham

Le paramétrage de la src d'une iframe nouvellement créée en javascript ne déclenche pas l'analyseur HTML tant que l'élément n'est pas inséré dans le document. Le code HTML est ensuite mis à jour et l'analyseur HTML est appelé et traite l'attribut comme prévu. 

http://jsfiddle.net/9k9Pe/2/

var iframe = document.createElement('iframe');
var html = '<body>Foo</body>';
iframe.src = 'data:text/html;charset=utf-8,' + encodeURI(html);
document.body.appendChild(iframe);
console.log('iframe.contentWindow =', iframe.contentWindow);

En outre, pour répondre à votre question, il est important de noter que cette approche pose des problèmes de compatibilité avec certains navigateurs. Veuillez consulter la réponse de @mschr pour une solution multi-navigateurs.

94
GillesC

Bien que votre src = encodeURI devrait fonctionner, j'aurais choisi une méthode différente:

var iframe = document.createElement('iframe');
var html = '<body>Foo</body>';
document.body.appendChild(iframe);
iframe.contentWindow.document.open();
iframe.contentWindow.document.write(html);
iframe.contentWindow.document.close();

Comme cela n’a pas de contrainte de domaine x et est complètement fait via le handle iframe, vous pourrez accéder et manipuler le contenu du cadre plus tard. Tout ce dont vous avez besoin de vous assurer, c’est que le contenu a été rendu, ce qui (selon le type de navigateur) commencera pendant/après l’émission de la commande .write - mais pas nécessairement fait lorsque close() est appelé.

Une méthode 100% compatible de faire un rappel pourrait être cette approche:

<html><body onload="parent.myCallbackFunc(this.window)"></body></html>

Iframes a cependant l'événement onload. Voici une approche pour accéder au code HTML intérieur en tant que DOM (js):

iframe.onload = function() {
   var div=iframe.contentWindow.document.getElementById('mydiv');
};
196
mschr

Merci pour votre excellente question, cela m’a surpris plusieurs fois. Lors de l'utilisation de source HTML dataURI, je constate que je dois définir un document HTML complet.

Voir ci-dessous un exemple modifié. 

var html = '<html><head></head><body>Foo</body></html>';
var iframe = document.createElement('iframe');
iframe.src = 'data:text/html;charset=utf-8,' + encodeURI(html);

prenez note du contenu HTML encapsulé avec les balises <html> et la chaîne iframe.src.

L'élément iframe doit être ajouté à l'arborescence DOM pour être analysé. 

document.body.appendChild(iframe);

Vous ne pourrez pas inspecter le iframe.contentDocument sauf si vous disable-web-security sur votre navigateur ... vous recevrez un message.

DOMException: impossible de lire la propriété 'contentDocument' à partir de 'HTMLIFrameElement': blocage d'un cadre avec Origin " http: // localhost: 7357 " pour accéder à un cadre d'origine croisée.

11
halfcube

Il existe une alternative pour créer un iframe dont le contenu est une chaîne de caractères HTML: l'attribut srcdoc . Ceci n'est pas pris en charge par les anciens navigateurs (parmi lesquels: Internet Explorer et éventuellement Safari ?), Mais il existe un polyfill pour ce comportement, que vous pouvez insérer dans des commentaires conditionnels pour IE quelque chose comme has.js pour le charger conditionnellement paresseux.

7
zedd45

Faire ceci

...
var el = document.getElementById('targetFrame');

var frame_win = getIframeWindow(el);

console.log(frame_win);
...

getIframeWindowest défini ici

function getIframeWindow(iframe_object) {
  var doc;

  if (iframe_object.contentWindow) {
    return iframe_object.contentWindow;
  }

  if (iframe_object.window) {
    return iframe_object.window;
  } 

  if (!doc && iframe_object.contentDocument) {
    doc = iframe_object.contentDocument;
  } 

  if (!doc && iframe_object.document) {
    doc = iframe_object.document;
  }

  if (doc && doc.defaultView) {
   return doc.defaultView;
  }

  if (doc && doc.parentWindow) {
    return doc.parentWindow;
  }

  return undefined;
}
0
Dominique Fortin