在框架窗口的上下文中运行代码

时间:2017-09-01 04:44:30

标签: javascript html browser

我想在iframe的窗口中运行一些javascript。现在,我能想到的唯一方法是注入脚本标记:

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

注意:这是一个同域iframe,没有src,因此我可以完全访问contentWindow

对于我的用例来说,重要的是代码运行正确的全局变量; windowdocument等都应限定为iframe本身。

还有其他方法吗?上述工作,但脚本需要在不同的域上运行所有具有不同的CSP规则,这意味着添加对nonce /哈希等的支持。

是否可以执行以下操作:

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

我已尝试myIframe.contentWindow.setTimeout,但似乎仍然在父窗口的上下文中运行代码。

4 个答案:

答案 0 :(得分:3)

您实际上可以创建run函数,然后将回调函数应用于this,当然这将是iframe上下文。然后,您可以使用this

访问iframe元素
myIframe.contentWindow.run = function(fn) {
    fn.apply(this);
};

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

控制台输出

(run) The current window name is: xyz123

您可以在此处查看我的示例:http://zikro.gr/dbg/html/con-frame/

修改

如果您只想使用window而不是this.window,那么您可以为内联函数创建一个名为window的参数,然后只需传递this.window像这样的功能:

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

它仍然按预期工作。

答案 1 :(得分:2)

也许将javascript拆分为从主窗口运行的部分(让我们称之为main.js)和iframe(让我们称之为iframe.js)。然后在iframe的src地点链接到iframe.jsiframe.html加载js文件(我不确定你是否可以直接从src添加javascript属性)。

如果您将js加载到iframe,请使用Calling a function inside an iframe from outside the iframe处的解决方案。

答案 2 :(得分: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);

使用Firefox和Chromium进行测试。

您可以将.src应用于frameScript,而不是.textContent,因此脚本可以异步加载。然后你可以调用postMessage,如上所示,或者调用一个回调函数来通知父窗口。

请注意,在原始代码window.frameElement.name中已初始化。然后您的脚本会询问window.name。 FireFox会自动将值复制到窗口,造成一些混淆。

答案 3 :(得分:1)

您需要异步加载脚本(即$.getScript()),然后在.contentWindow上调用它。我没有测试,但这应该有用。

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

如果此解决方案不起作用,这两个资源将会有所帮助: https://plainjs.com/javascript/ajax/load-a-script-file-asynchronously-49/

Invoking JavaScript code in an iframe from the parent page