为了理解您的代码为什么不起作用,我附上了我之前回答的片段:
内容脚本无权访问页面的全局window
对象。对于内容脚本,以下适用:
- 该
window
变量不引用页面的全局对象。相反,它指的是一个新的上下文,一个页面上的“层”。页面的 DOM 是完全可访问的。#执行环境
给定一个包含以下内容的文档 <iframe id="frameName" src="http://domain/"></iframe>
:
- 对框架内容的访问受到页面同源策略的限制;您的扩展程序的权限不会放松政策。
frames[0]
和frames['frameName']
,(通常指帧的包含全局window
对象)是undefined
.
var iframe = document.getElementById('frameName');
iframe.contentDocument
返回document
包含框架的对象,因为内容脚本可以访问页面的 DOM。此属性null
适用于同源策略。
iframe.contentDocument.defaultView
(指window
与文档关联的对象)未定义。
iframe.contentWindow
是未定义的。
同源帧的解决方案
在您的情况下,以下任一方法都可以:
// jQuery:
$("#iframe1").contents()[0].execCommand( ... );
// VanillaJS
document.getElementById("iframe1").contentDocument.execCommand( ... );
// "Unlock" contentWindow property by injecting code in context of page
var s = document.createElement('script');
s.textContent = 'document.getElementById("iframe1").contentWindow.document.execCommand( ... );';
document.head.appendChild(s);
通用解决方案
通用解决方案"all_frames": true
在清单文件中使用,并使用如下内容:
if (window != top) {
parent.postMessage({fromExtension:true}, '*');
addEventListener('message', function(event) {
if (event.data && event.data.inserHTML) {
document.execCommand('insertHTML', false, event.data.insertHTML);
}
});
} else {
var test_html = 'test string';
// Explanation of injection at https://stackoverflow.com/a/9517879/938089 :
// Run code in the context of the page, so that the `contentWindow`
// property becomes accessible
var script = document.createElement('script');
script.textContent = '(' + function(s_html) {
addEventListener('message', function(event) {
if (event.data.fromExtension === true) {
var iframe = document.getElementById('iframe1');
if (iframe && (iframe.contentWindow === event.source)) {
// Window recognised, post message back
iframe.contentWindow.postMessage({insertHTML: s_html}, '*');
}
}
});
} + ')(' + JSON.stringify(test_html) + ');';
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);
}
此演示仅用于教育目的,请勿在实际扩展中使用此演示。为什么?因为它postMessage
用来传递消息。这些事件也可以由客户端生成,从而导致安全漏洞(XSS:任意 HTML 注入)。
替代方案postMessage
是 Chrome 的消息 API。有关演示,请参阅此答案。但是,您将无法比较这些window
对象。你能做的就是依靠window.name
财产。该window.name
属性会自动设置为 iframename
属性的值(仅在加载 iframe 时设置一次)。