可以从Chrome扩展修改窗口对象吗
Can the window object be modified from a Chrome extension?
我想做一个Chrome扩展,在window
中提供一个新对象。当在加载了扩展的浏览器中查看网页时,我希望window.mything
可以通过Javascript使用。window.mything
对象将有一些我将在扩展中定义的函数,当在启用了扩展的浏览器中查看页面时,这些函数应该可以从console.log
或任何Javascript文件中调用。
我能够通过使用内容脚本成功地将Javascript文件注入页面:
var s = document.createElement("script");
s.src = chrome.extension.getURL("mything.js");
document.getElementsByTagName("head")[0].appendChild(s);
mything.js看起来像这样:
window.mything = {thing: true};
console.log(window);
每当加载页面时,我都会在控制台中看到整个window
对象。但是,我无法从控制台与window.mything
对象进行交互。似乎注入的脚本并没有真正修改全局window
对象。
如何从Chrome扩展修改全局window
对象?
你不能,不能直接。来自内容脚本文档:
但是,内容脚本有一些局限性。他们不能:
- 使用chrome.*API(chrome.extension的部分除外)
- 使用由其扩展页面定义的变量或函数
- 使用网页或其他内容脚本定义的变量或函数
(增加重点)
内容脚本看到的window
对象与页面看到的window
对象不同。
但是,您可以使用window.postMessage
方法通过DOM传递消息。页面和内容脚本都会侦听消息事件,无论何时从其中一个位置调用window.postMessage
,另一个位置都会收到它。"内容脚本"文档页面上有一个示例。
编辑:您可以通过从内容脚本中注入脚本来向页面添加一些方法。如果不使用postMessage
之类的东西,它仍然无法与扩展的其余部分进行通信,但您至少可以在页面的window
中添加一些内容
var elt = document.createElement("script");
elt.innerHTML = "window.foo = {bar:function(){/*whatever*/}};"
document.head.appendChild(elt);
在尝试了几个小时的不同尝试并面临CORS等安全问题后,我找到了在Chrome
、Firefox
和Safari
上编辑window
对象的方法。你需要为每种策略使用不同的策略:
铬
- 将您的脚本添加到
content_scripts
- 在脚本文件中,将
script
附加到页面上,并使其内联运行您的自定义代码。像这样:
;(function() {
function script() {
// your main code here
window.foo = 'bar'
}
function inject(fn) {
const script = document.createElement('script')
script.text = `(${fn.toString()})();`
document.documentElement.appendChild(script)
}
inject(script)
})()
Firefox
在Firefox上,由于Content-Security-Policy
错误,上述解决方案不起作用。但以下变通方法目前正在发挥作用,至少目前是这样:
- 向
content_scripts
添加2个脚本,例如inject.js
和script.js
inject
脚本将获得script.js
文件的完整绝对url并加载它:
;(function() {
const b = typeof browser !== 'undefined' ? browser : chrome
const script = document.createElement('script')
script.src = b.runtime.getURL('script.js')
document.documentElement.appendChild(script)
})()
- 您的
script.js
将包含您的主代码:
;(function() {
// your main code here
window.foo = 'bar'
})()
Safari
它与Firefox非常相似。
- 创建2个javascript文件,例如
inject.js
和script.js
inject
脚本将获得script.js
文件的完整绝对url并加载它:
;(function() {
const script = document.createElement('script')
script.src = safari.extension.baseURI + 'script.js'
document.documentElement.appendChild(script)
})()
- 您的
script.js
将包含您的主代码:
;(function() {
// your main code here
window.foo = 'bar'
})()
源代码
请在此处查看完整代码:https://github.com/brunolemos/simplified-twitter
正如其他人所指出的,上下文脚本与页面的上下文不在同一上下文中运行,因此,要访问正确的window
,需要向页面中注入代码。
以下是我的看法:
function codeToInject() {
// Do here whatever your script requires. For example:
window.foo = "bar";
}
function embed(fn) {
const script = document.createElement("script");
script.text = `(${fn.toString()})();`;
document.documentElement.appendChild(script);
}
embed(codeToInject);
清洁且易于使用。无论你需要在页面的上下文中运行什么,都可以把它放在codeToInject()
中(你可以随意称呼它)。embed()
函数负责打包函数并将其发送到页面中运行。
embed()
函数的作用是在页面中创建一个script
标记,并将函数codeToInject()
作为IIFE嵌入其中。一旦新的script
标记被附加到文档中,浏览器就会立即执行它,并且您注入的代码将按预期在页面的上下文中运行。
chrome扩展的content_script
在其独立于窗口的上下文中运行。不过,您可以将脚本注入页面,使其在与页面窗口相同的上下文中运行,如下所示:Chrome扩展-从网页检索全局变量
我能够调用窗口对象上的方法,并通过在页面的DOM:中添加script.js
来修改窗口属性
var s = document.createElement('script');
s.src = chrome.extension.getURL('script.js');
(document.head||document.documentElement).appendChild(s);
s.onload = function() {
s.remove();
};
并在注入的脚本文件中创建自定义事件侦听器:
document.addEventListener('_my_custom_event', function(e) {
// do whatever you'd like! Like access the window obj
window.myData = e.detail.my_event_data;
})
并在content_script:中调度该事件
var foo = 'bar'
document.dispatchEvent(new CustomEvent('_save_OG_Editor', {
'detail': {
'my_event_data': foo
}
}))
反之亦然;在script.js
中调度事件,并在扩展的content_script中侦听它们(如上面的链接所示)。
只要确保将注入的脚本添加到扩展的文件中,并将脚本文件的路径添加到"web_accessible_resources"
中的清单中,否则就会出现错误。
希望能帮助别人◡•)/
我一直在玩这个。我发现我可以通过将javascript包装到window.location=调用中来与浏览器的window对象进行交互。
var myInjectedJs = "window.foo='This exists in the ''real'' window object';"
window.location = "javascript:" + myInjectedJs;
var myInjectedJs2 = "window.bar='So does this.';"
window.location = "javascript:" + myInjectedJs2;
它有效,但仅适用于正在设置的window.location的最后一个实例。如果您访问文档的窗口对象,它将有一个变量"bar",而不是"foo"
感谢这里的其他答案,这就是我使用的:
((source)=>{
const script = document.createElement("script");
script.text = `(${source.toString()})();`;
document.documentElement.appendChild(script);
})(function (){
// Your code here
// ...
})
效果很好,没有问题。
内容脚本可以调用window
方法,然后可以使用这些方法来更改window
对象。这比<script>
标签注入更容易,并且即使在<head>
和<body>
尚未被解析时(例如,当使用run_at: document_start
时)也能工作。
// In Content Script
window.addEventListener('load', loadEvent => {
let window = loadEvent.currentTarget;
window.document.title='You changed me!';
});
- 如何在选项卡上定义属性'的主窗口对象
- 可以从Chrome扩展修改窗口对象吗
- 在Backbone.js中为窗口对象指定变量
- 从html锚元素传递窗口对象
- 如何在ReactJS中使用窗口对象
- 在加载时调用时,窗口对象的某些变量丢失
- 清除 Javascript 中窗口对象中的自定义变量
- 窗口对象属性返回一个dom节点
- 使用窗口对象练习我的对象文字函数
- 如何从Chrome扩展访问所有窗口对象
- Jasmine在全局窗口对象上创建本地JS函数的Spy
- 如何使用Chrome'查看窗口对象中定义了哪些变量;的开发工具
- 有没有一种方法可以强制浏览器's窗口对象以重新评估鼠标所在的位置
- Safari 在尝试使用 Javascript try/catch 访问父窗口对象时未捕获异常
- 测试使用 jQuery 和窗口对象的 React 组件
- 迭代窗口对象时出现“'window.webkitStorageInfo' is deprecated”警
- 窗口对象通过对象类型测试,但 hasOwnProperty 导致错误
- node.js是否等同于浏览器中的窗口对象
- 页面工作线程 - destroy() 似乎没有删除窗口对象
- 全局变量只是“窗口”对象的属性吗?