Javascript 可以从 Chrome 扩展程序修改窗口对象吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12395722/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can the window object be modified from a Chrome extension?
提问by Zach Rattner
I would like to make a Chrome extension that provides a new object inside window
. When a web page is viewed in a browser with the extension loaded, I would like window.mything
to be available via Javascript. The window.mything
object will have some functions that I will define in the extension, and these functions should be callable from console.log
or any Javascript file when the page is viewed in a browser with the extension enabled.
我想制作一个 Chrome 扩展程序,在window
. 当在加载了扩展程序的浏览器中查看网页时,我希望window.mything
通过 Javascript 可用。该window.mything
对象将具有一些我将在扩展中定义的函数,console.log
当在启用了扩展的浏览器中查看页面时,这些函数应该可以从Javascript 文件或任何 Javascript 文件中调用。
I was able to successfully inject a Javascript file into the page by using a Content Script:
我能够使用内容脚本成功地将 Javascript 文件注入页面:
var s = document.createElement("script");
s.src = chrome.extension.getURL("mything.js");
document.getElementsByTagName("head")[0].appendChild(s);
mything.js looks like this:
mything.js 看起来像这样:
window.mything = {thing: true};
console.log(window);
Whenever a page loads, I see the entire window
object as I expect it to be in the console. However, I can't interact with the window.mything
object from the console. It seems at if the injected script hasn't really modified the global window
object.
每当页面加载时,我window
都会在控制台中看到我期望的整个对象。但是,我无法window.mything
从控制台与对象进行交互。似乎注入的脚本并没有真正修改全局window
对象。
How can I modify the global window
object from a Chrome extension?
如何window
从 Chrome 扩展程序修改全局对象?
回答by nynexman4464
You can't, not directly. From the content scripts documentation:
你不能,不能直接。从内容脚本文档:
However, content scripts have some limitations. They cannot:
- Use chrome.* APIs (except for parts of chrome.extension)
- Use variables or functions defined by their extension's pages
- Use variables or functions defined by web pages or by other content scripts
但是,内容脚本有一些限制。他们不可以:
- 使用 chrome.* API(除了 chrome.extension 的部分)
- 使用由其扩展页面定义的变量或函数
- 使用由网页或其他内容脚本定义的变量或函数
(emphasis added)
(强调)
The window
object the content script sees is not the same window
object that the page sees.
该window
内容脚本看到的对象是不一样的window
对象,它的页面看到。
You can pass messages via the DOM, however, by using the window.postMessage
method. Both your page and content script listen to the messageevent, and whenever you call window.postMessage
from one of those places, the other will receive it. There's an example of thison the "Content Scripts" documentation page.
但是,您可以使用window.postMessage
方法通过 DOM 传递消息。您的页面和内容脚本都会监听message事件,无论何时您window.postMessage
从其中一个地方调用,另一个都会收到它。“内容脚本”文档页面上有一个示例。
edit:
You could potentially add some methods to the page by injecting a script from the content script. It still wouldn't be able to communicate back with the rest of the extension though, without using something like postMessage
, but you could at least add some things to the page's window
编辑:您可以通过从内容脚本中注入脚本来向页面添加一些方法。它仍然无法与扩展的其余部分进行通信,而不使用类似的东西postMessage
,但您至少可以向页面的window
var elt = document.createElement("script");
elt.innerHTML = "window.foo = {bar:function(){/*whatever*/}};"
document.head.appendChild(elt);
回答by Bruno Lemos
After hours trying different attempts and facing security issues like CORS, I found ways to edit the window
object on Chrome
, Firefox
and Safari
. You need to use different strategies for each one:
经过数小时尝试不同的尝试并面临 CORS 等安全问题后,我找到了window
在Chrome
、Firefox
和上编辑对象的方法Safari
。您需要对每个策略使用不同的策略:
Chrome
铬合金
- Add your script to
content_scripts
. - Inside your script file, append a
script
to the page and make it run your custom code inline. Like this:
- 将您的脚本添加到
content_scripts
. - 在您的脚本文件中,将 a 附加
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
火狐
On Firefox, the solution above doesn't work due to a Content-Security-Policy
error. But the following workaround is currently working, at least for now:
在 Firefox 上,由于Content-Security-Policy
错误,上述解决方案不起作用。但以下解决方法目前正在发挥作用,至少目前是这样:
- Add 2 scripts to
content_scripts
, e.g.inject.js
andscript.js
- The
inject
script will get the full absolute urlof thescript.js
file and load it:
- 将 2 个脚本添加到
content_scripts
,例如inject.js
和script.js
- 该
inject
脚本将获得完整的绝对URL中的script.js
文件并加载它:
;(function() {
const b = typeof browser !== 'undefined' ? browser : chrome
const script = document.createElement('script')
script.src = b.runtime.getURL('script.js')
document.documentElement.appendChild(script)
})()
- Your
script.js
will contain your main code:
- 您
script.js
将包含您的主要代码:
;(function() {
// your main code here
window.foo = 'bar'
})()
Safari
苹果浏览器
It's very similar to Firefox.
它与 Firefox 非常相似。
- Create 2 javascript files, e.g.
inject.js
andscript.js
- The
inject
script will get the full absolute urlof thescript.js
file and load it:
- 创建 2 个 javascript 文件,例如
inject.js
和script.js
- 该
inject
脚本将获得完整的绝对URL中的script.js
文件并加载它:
;(function() {
const script = document.createElement('script')
script.src = safari.extension.baseURI + 'script.js'
document.documentElement.appendChild(script)
})()
- Your
script.js
will contain your main code:
- 您
script.js
将包含您的主要代码:
;(function() {
// your main code here
window.foo = 'bar'
})()
Source code
源代码
See full code here: https://github.com/brunolemos/simplified-twitter
在此处查看完整代码:https: //github.com/brunolemos/simplified-twitter
回答by Kevin Hagerty
I've been playing around with this. I found that I can interact with the window object of the browser by wrapping my javascript into a window.location= call.
我一直在玩这个。我发现我可以通过将我的 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;
It works, but only for the last instance of window.location being set. If you access the document's window object, it will have a variable "bar" but not "foo"
它有效,但仅适用于设置的 window.location 的最后一个实例。如果您访问文档的 window 对象,它将有一个变量“bar”而不是“foo”
回答by ztrat4dkyle
A chrome extension's content_script
runs within its own context which is separate from the window. You can inject a script into the page though so it runs in the same context as the page's window, like this: Chrome extension - retrieving global variable from webpage
chrome 扩展程序content_script
在其自己的上下文中运行,该上下文与窗口分开。您可以将脚本注入页面,以便它在与页面窗口相同的上下文中运行,如下所示:Chrome 扩展程序 - 从网页中检索全局变量
I was able to call methods on the window object and modify window properties by essentially adding a script.js
to the page's DOM:
我能够调用 window 对象上的方法并通过将 a 添加script.js
到页面的 DOM 来修改窗口属性:
var s = document.createElement('script');
s.src = chrome.extension.getURL('script.js');
(document.head||document.documentElement).appendChild(s);
s.onload = function() {
s.remove();
};
and creating custom event listeners in that injected script file:
并在该注入的脚本文件中创建自定义事件侦听器:
document.addEventListener('_my_custom_event', function(e) {
// do whatever you'd like! Like access the window obj
window.myData = e.detail.my_event_data;
})
and dispatching that event in the content_script:
并在 content_script 中调度该事件:
var foo = 'bar'
document.dispatchEvent(new CustomEvent('_save_OG_Editor', {
'detail': {
'my_event_data': foo
}
}))
or vice versa; dispatch events in script.js
and listen for them in your extension's content_script (like the above link illustrates well).
或相反亦然; script.js
在您的扩展的 content_script 中分派事件并监听它们(就像上面的链接很好地说明了一样)。
Just be sure to add your injected script within your extension's files, and add the script file's path to your manifest within "web_accessible_resources"
or you'll get an error.
只需确保将注入的脚本添加到扩展文件中,并将脚本文件的路径添加到其中的清单中,"web_accessible_resources"
否则会出现错误。
Hope that helps someone \ (???) /
希望对某人有所帮助\(???)/
回答by Lucio Paiva
As others pointed out, context scripts do not run in the same context as the page's, so, to access the correct window
, you need to inject code into the page.
正如其他人指出的那样,上下文脚本不会在与页面相同的上下文中运行,因此,要访问正确的window
,您需要将代码注入页面。
Here's my take at it:
这是我的看法:
function runEmbedded() {
// Put here whatever your script needs to do. For example:
window.foo = "bar";
}
function embed(fn) {
const script = document.createElement("script");
script.text = `(${fn.toString()})();`;
document.documentElement.appendChild(script);
}
embed(runEmbedded);
Clean and easy to use. Whatever you need to run in the page's context, put it in runEmbedded()
(you may call it whatever you prefer). The embed()
function takes care of packaging your function and sending it to run in the page.
清洁且易于使用。无论您需要在页面上下文中运行什么,都将其放入runEmbedded()
(您可以随意称呼它)。该embed()
函数负责打包您的函数并将其发送到页面中运行。
回答by Joseph Lust
Content Scripts cancall window
methods which can then be used to mutate the window
object. This is easier than <script>
tag injection and works even when the <head>
and <body>
haven't yet been parsed (e.g. when using run_at: document_start
).
内容脚本可以调用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!';
});