2017-09-01 7 views
5

Ich möchte etwas Javascript im Kontext eines Iframe-Fensters ausführen. Im Augenblick ist die einzige Möglichkeit, die ich denken kann, das zu tun ist ein Skript-Tag zu injizieren:Code im Kontext des Frame-Fensters ausführen

myIframe = document.createElement('iframe'); 
myIframe.setAttribute('name', 'xyz123'); 
document.body.appendChild(myIframe); 

myIframe.contentWindow.document.write(` 
    <script> 
     console.log('The current window name is:', window.name); 
    </script> 
`); 

Hinweis: Dies ist ein gleich Domain iframe, ohne src, so habe ich vollen Zugriff auf die contentWindow.

Es ist wichtig für meinen Anwendungsfall, dass der Code mit den richtigen Globals ausgeführt wird; window, document usw. sollten alle auf den iframe selbst beschränkt sein.

Gibt es eine andere Möglichkeit, das kann ich tun? Die oben genannten Arbeiten, aber das Skript muss auf verschiedenen Domänen alle mit unterschiedlichen CSP Regeln laufen, die Stützmittel für das Hinzufügen Nonces/Hashes usw.

Ist es möglich, so etwas wie zu tun:

myIframe.contentWindow.run(function() { 
    console.log('The current window name is:' window.name); 
}); 

I‘ habe versucht, myIframe.contentWindow.setTimeout, aber das scheint immer noch den Code im Kontext des übergeordneten Fensters ausführen.

Antwort

2

Vielleicht teilen Sie das Javascript in Teil vom Hauptfenster (nennen wir es main.js) und von iframe (nennen wir es iframe.js). Dann in Iframe src Ort Link zu iframe.js oder iframe.html, die js-Datei lädt (Ich bin nicht sicher, ob Sie Javascript direkt aus src Attribut enthalten).

Wenn Sie js in den iframe laden, verwenden Sie die Lösung unter Calling a function inside an iframe from outside the iframe.

+0

Danke für die Anregung - aber für meinen Anwendungsfall, ich muss in der Lage sein einfügen Beliebiges Javascript in den Frame, der nicht unbedingt irgendwo gehostet wird - daher das Script-Tag. – bluepnume

2

Sie können diese run Funktion tatsächlich erstellen und dann eine Rückruffunktion auf this anwenden, die natürlich der Iframe-Kontext sein wird. Dann können Sie iframe-Elemente zugreifen, indem this mit:

myIframe.contentWindow.run = function(fn) { 
    fn.apply(this); 
}; 

myIframe.contentWindow.run(function() { 
    console.log('(run) The current window name is:', this.window.name); 
}); 

Konsolenausgabe

(run) The current window name is: xyz123 

Sie meinem Beispiel hier überprüfen: http://zikro.gr/dbg/html/con-frame/

EDIT

Wenn Sie möchten, um einfachzu verwendenstatt this.window, dann können Sie einen Parameter an die Inline-Funktion erstellen mit ihm window nennen, und dann this.window einfach so zu dieser Funktion übergeben:

myIframe.contentWindow.run = function(fn) { 
    fn.call(this, this.window); 
}; 

myIframe.contentWindow.run(function(window) { 
    console.log('(run) The current window name is:', window.name); 
}); 

Und es funktioniert immer noch wie erwartet.

+0

Dies ist ein großartiges Beispiel - das einzige Problem ist, dass es die Semantik aller Funktionen ändert, die im Iframe vorhanden sein werden, um "this.window" anstatt "window" zu referenzieren - aber das ist definitiv die beste Antwort weit. Vielen Dank! – bluepnume

+0

@bluepnume du bist willkommen. Ich habe meine Antwort aktualisiert, um eine Inline-Funktion zu haben, die einen Parameter mit dem Namen 'window' enthält, den Sie verwenden können; es beseitigt die Notwendigkeit, "this.window" zu verwenden. Dies funktioniert nur, wenn Sie die gesamte Inline-Funktion explizit von einer bestimmten Quelle anwenden lassen müssen, die dann nicht diesen spezifischen Parameter haben kann. –

1
window.name='main window'; // just for debugging 
var myIframe = document.createElement('iframe'), frameScript = document.createElement('script'); 
document.body.appendChild(myIframe); 
frameScript.textContent = "window.top.name='topWindow';window.name = 'xyz123';function WhereAmI(){return(window.name);} window.parent.postMessage('frame_initialized', '*'); " 
myIframe.contentWindow.document.documentElement.appendChild(frameScript); 
function OnMessage(event) { 
    if(typeof event.data == 'string') switch(event.data) { 
    case 'frame_initialized': 
    myIframe.contentWindow.document.body.appendChild(document.createTextNode(myIframe.contentWindow.WhereAmI())); 
    console.log('Now running in', myIframe.contentWindow.WhereAmI()); 
    break; 
    } 
} 
window.addEventListener('message', OnMessage, false); 

Getestet mit Firefox und Chromium.

Anstelle von .textContent können Sie die .src auf frameScript anwenden, damit das Skript asynchron geladen werden kann. Dann können Sie postMessage wie oben gezeigt aufrufen oder eine Callback-Funktion aufrufen, um das übergeordnete Fenster zu benachrichtigen.

Beachten Sie, dass in Ihrem ursprünglichen Code window.frameElement.name initialisiert wird.Ihr Skript fragt dann nach window.name. FireFox kopiert den Wert automatisch in das Fenster, was zu einiger Verwirrung führt.

+0

Um diese Antwort zu verbessern, muss ich Ihr Szenario besser verstehen. Haben Sie Zugriff auf den HTML-Code in beiden Domains? Sollte es nur für dich vor Ort oder für alle laufen? Ist der Einsatz eines Skript-Managers wie GreaseMonkey möglich? – gnblizz

+0

Danke für den Vorschlag, aber ich bin nicht sicher, window.postMessage würde mir speziell helfen, willkürlichen Code in den Rahmen zu führen - ich würde eine Möglichkeit brauchen, um einen Nachrichten-Listener in den Rahmen zu fügen, damit dies funktioniert, was mich bringt zurück zum ursprünglichen Problem. – bluepnume

+0

Um Ihre Frage zu beantworten, muss dies für alle funktionieren, damit der Fettmonitor nicht funktioniert. Es gibt keine zweite Domain - der Iframe wird ohne 'src' geladen – bluepnume

1

Sie müssen das Skript asynchron laden (d. H. $.getScript()) und dann unter .contentWindow aufrufen. Ich habe nicht getestet, aber das sollte funktionieren.

(function() { 

    var myIframe = document.createElement('iframe#iframe'): 

    var jsSnippet; 
    var iframeScript = function(url) { 
     script = document.createElement('script'), 
     scripts = document.getElementsByTagName('script')[0]; 
     script.src = url; 
     return jsSnippet = scripts.parentNode.insertBefore(script, scripts); 
    }; 

    myIframe.setAttribute('name', 'xyz123'): 
    myIframe.appendChild(jsSnippet); 
    document.body.appendChild(myIframe); 
    return document.getElementById('#iframe').contentWindow.iframeScript(); 
}) 

Diese beiden Ressourcen hilfreich sein, wenn diese Lösung nicht funktioniert: https://plainjs.com/javascript/ajax/load-a-script-file-asynchronously-49/

Invoking JavaScript code in an iframe from the parent page

Verwandte Themen