web-dev-qa-db-fra.com

Pourquoi l'ajout d'un <script> à un <iframe> créé dynamiquement semble-t-il exécuter le script dans la page parent?

J'essaie de créer un <iframe> à l'aide de JavaScript, puis d'ajouter un élément <script> à ce <iframe>, que je veux exécuter dans le contexte du document <iframe> d.

Malheureusement, il semble que je fasse quelque chose de mal - mon JavaScript semble s'exécuter correctement, mais le contexte du <script> est la page parent, pas le document <iframe> d. J'obtiens également une erreur 301 dans l'onglet "Net" de Firebug lorsque le navigateur demande iframe_test.js , bien qu'il le demande ensuite à nouveau (vous ne savez pas pourquoi?) avec succès.

Voici le code que j'utilise (démo en direct sur http://onespot.wsj.com/static/iframe_test.html ):

iframe_test.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>&lt;iframe&gt; test</title>
  </head>
  <body>
    <div id="bucket"></div>
    <script type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js"></script>
    <script type="text/javascript">
      $(document).ready(function() {
        $('#bucket').append('<iframe id="test"></iframe>');
        setTimeout(function() {
          var iframe_body = $('#test').contents().find('body');
          iframe_body.append('<scr' + 'ipt type="text/javascript" src="http://onespot.wsj.com/static/iframe_test.js"></scr' + 'ipt>');
        }, 100);
      });
    </script>
  </body>
</html>

iframe_test.js

$(function() {
  var test = '<p>Shouldn\'t this be inside the &lt;iframe&gt;?</p>';
  $('body').append(test);
});

Une chose qui semble inhabituelle est que le code dans iframe_test.js fonctionne même; Je n'ai pas chargé jQuery dans le <iframe> lui-même, uniquement dans le document parent. Cela me semble être un indice, mais je n'arrive pas à comprendre ce que cela signifie.

Toutes les idées, suggestions, etc. seraient très appréciées!

45
Bungle

J'ai eu le même problème, il m'a fallu des heures pour trouver la solution. Vous avez juste besoin de créer l'objet du script en utilisant le document iframe.

var myIframe = document.getElementById("myIframeId");
var script = myIframe.contentWindow.document.createElement("script");
script.type = "text/javascript";
script.src = src;
myIframe.contentWindow.document.body.appendChild(script);

Fonctionne comme un charme!

70
Oleg Grishko

Je n'ai pas trouvé de réponse à ma question initiale, mais j'ai trouvé une autre approche qui fonctionne encore mieux (au moins pour mes besoins).

Cela n'utilise pas jQuery sur la page parent (ce qui est en fait une bonne chose, car je préfère ne pas le charger ici), mais il charge jQuery dans le <iframe> d'une manière apparemment complètement valide et utilisable. Tout ce que je fais, c'est écrire sur l'objet document de <iframe> avec un nouveau créé à partir de zéro. Cela me permet d'inclure simplement un élément <script> dans une chaîne que j'écris ensuite dans l'objet document de <iframe>.

Le code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>frame</title>
  </head>
  <body>

    <div id="test"></div>

    <script type="text/javascript">
      // create a new <iframe> element
      var iframe = document.createElement('iframe');

      // append the new element to the <div id="bucket"></div>
      var bucket = document.getElementById('test');
      bucket.appendChild(iframe);

      // create a string to use as a new document object
      var val = '<scr' + 'ipt type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js"></scr' + 'ipt>';
      val += '<scr' + 'ipt type="text/javascript"> $(function() { $("body").append("<h1>It works!</h1>"); }); </scr' + 'ipt>';

      // get a handle on the <iframe>d document (in a cross-browser way)
      var doc = iframe.contentWindow || iframe.contentDocument;
      if (doc.document) {
        doc = doc.document;
      }

      // open, write content to, and close the document
      doc.open();
      doc.write(val);
      doc.close();
    </script>

  </body>
</html>

J'espère que cela aide quelqu'un sur la route!

16
Bungle

La réponse à la question d'origine est simple - l'exécution du script se fait par jquery, et puisque jquery est chargé dans le cadre supérieur, c'est là que le script s'exécute également, peu importe où vous l'ajoutez. Une implémentation plus intelligente de jquery peut sans aucun doute être faite pour utiliser l'objet fenêtre correct, mais pour l'instant les choses sont comme elles sont.

En ce qui concerne les solutions de contournement, vous avez déjà deux bonnes réponses (même si l'une est la vôtre). Ce que je pourrais ajouter, c'est que vous pouvez utiliser l'une de ces solutions de contournement pour inclure jquery.js dans l'iframe, puis obtenir cet objet jquery au lieu de celui du haut pour insérer votre balisage supplémentaire ... mais cela peut très bien être excessif aussi.

0
user2107721