admin管理员组

文章数量:1336107

I'd like to run some javascript in the context of an iframe's window. Right now the only way I can think to do that is to inject a script tag:

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

Note: this is a same-domain iframe, without a src, so I have full access to the contentWindow.

It's important for my use case that the code runs with the correct globals; window, document etc should all be scoped to the iframe itself.

Is there any other way I can do this? The above works, but the script needs to run on different domains all with different CSP rules, which means adding support for nonces/hashes etc.

Is it possible to do something like:

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

I've tried myIframe.contentWindow.setTimeout but that still seems to run the code in the context of the parent window.

I'd like to run some javascript in the context of an iframe's window. Right now the only way I can think to do that is to inject a script tag:

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

Note: this is a same-domain iframe, without a src, so I have full access to the contentWindow.

It's important for my use case that the code runs with the correct globals; window, document etc should all be scoped to the iframe itself.

Is there any other way I can do this? The above works, but the script needs to run on different domains all with different CSP rules, which means adding support for nonces/hashes etc.

Is it possible to do something like:

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

I've tried myIframe.contentWindow.setTimeout but that still seems to run the code in the context of the parent window.

Share Improve this question asked Sep 1, 2017 at 4:44 bluepnumebluepnume 17.2k8 gold badges41 silver badges48 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 3 +200

You can actually create that run function, and then apply a callback function to this which of course will be the iframe context. Then you can access iframe elements by using this:

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

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

Console output

(run) The current window name is: xyz123

You can check my example here: http://zikro.gr/dbg/html/con-frame/

EDIT

If you want to just use window rather than this.window, then you can create a parameter to the inline function with he name window, and then just pass this.window to that function like this:

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

And it still works as expected.

Maybe split the javascript to part run from main window (let's call it main.js) and from iframe (let's call it iframe.js). Then in iframe's src place link to iframe.js or iframe.html which loads js file (I'm not sure if you can include javascript straight from src attribute).

If you load js into the iframe, use solution at Calling a function inside an iframe from outside the iframe.

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

Tested with Firefox and Chromium.

Instead of .textContent you can apply the .src to frameScript, so the script can load asynchronously. Then you can call postMessage as shown above or call a callback function to notify the parent window.

Note that in your original code window.frameElement.name is initialized. Your script asks then for window.name. FireFox copies the value automatically to the window, causing some confusion.

You need to load the script asynchronously (i.e. $.getScript()) and then invoke it on .contentWindow. I haven't tested but this should work.

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

These two resources will be helpful if this solution doesn't work: https://plainjs./javascript/ajax/load-a-script-file-asynchronously-49/

Invoking JavaScript code in an iframe from the parent page

本文标签: javascriptRun code in context of frame windowStack Overflow