我想在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
。
对于我的用例来说,重要的是代码运行正确的全局变量; window
,document
等都应限定为iframe本身。
还有其他方法吗?上述工作,但脚本需要在不同的域上运行所有具有不同的CSP规则,这意味着添加对nonce /哈希等的支持。
是否可以执行以下操作:
myIframe.contentWindow.run(function() {
console.log('The current window name is:' window.name);
});
我已尝试myIframe.contentWindow.setTimeout
,但似乎仍然在父窗口的上下文中运行代码。
答案 0 :(得分:3)
您实际上可以创建run
函数,然后将回调函数应用于this
,当然这将是iframe上下文。然后,您可以使用this
:
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.js
或iframe.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/