web-dev-qa-db-fra.com

injecter une fonction javascript dans un Iframe

Ce lien ( version archivée ) décrit comment injecter du code à partir d'un script dans un iframe:

function injectJS() {
  var iFrameHead = window.frames["myiframe"].document.getElementsByTagName("head")[0];
  var myscript = document.createElement('script');
  myscript.type = 'text/javascript';
  myscript.src = 'myscript.js'; // replace this with your SCRIPT
  iFrameHead.appendChild(myscript);
}

C'est ok, mais que faire si je veux insérer un objet fonction dans un iframe et le faire exécuter dans le contexte iframe? Disons que j'ai:

function foo () {
    console.log ("Look at me, executed inside an iframe!", window);
}

et je veux insérer le code de foo dans un iframe? ( la fonction foo pourrait être quelque chose chargée dynamiquement, je ne peux pas simplement la mettre entre guillemets )

J'ai naïvement essayé:

var scriptFooString = "<script>" + foo.toString() + "</script>"

pour obtenir le code à l'intérieur de la fonction, mais

  • Je ne sais pas comment l'insérer dans l'iframe HEAD (peut-être avec jquery?)
  • Je ne sais pas si c'est la bonne façon
  • Je ne sais pas ce qui se passe quand la fonction est bien plus complexe que ça
  • Je ne sais pas ce qui se passe avec les guillemets doubles et simples dans scriptFooString

Un indice?

30
janesconference

Tout d'abord, vous ne pouvez accomplir cela que si votre cadre et la page qui l'affiche se trouvent dans le même domaine (en raison de règles inter-domaines)

deuxièmement, vous pouvez manipuler les objets dom et window du cadre directement via JS:

frames[0].window.foo = function(){
   console.log ("Look at me, executed inside an iframe!", window);
}

pour obtenir votre cadre à partir d'un objet DOMElement, vous pouvez utiliser:

var myFrame = document.getElementById('myFrame');

myFrame.contentWindow.foo = function(){
       console.log ("Look at me, executed inside an iframe!");
}

Notez que la portée de foo n'est PAS modifiée, donc la fenêtre est toujours la fenêtre parente, etc. à l'intérieur de foo.

Si vous souhaitez injecter du code qui doit être exécuté dans le contexte de l'autre cadre, vous pouvez injecter une balise de script, ou l'évaluer:

frames[0].window.eval('function foo(){ console.log("Im in a frame",window); }');

Bien que le consensus général soit de ne jamais utiliser eval, je pense que c'est une meilleure alternative que l'injection DOM si vous avez VRAIMENT besoin d'accomplir cela.

Donc, dans votre cas spécifique, vous pourriez faire quelque chose comme:

frames[0].window.eval(foo.toString());
32
EJTH

Voici ma solution. J'utilise jquery pour insérer le contenu, puis j'utilise eval pour exécuter les balises de script dans le contexte de cette iframe:

    var content = $($.parseHTML(source, document, true));
    $("#content").contents().find("html").html(content);
    var cw = document.getElementById("content").contentWindow;
    [].forEach.call(cw.document.querySelectorAll("script"), function (el, idx) {
        cw.eval(el.textContent);
    });
2
frumbert