Javascript 将 JS 函数从 Chrome 上的 Greasemonkey 脚本注入页面

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2303147/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 23:40:59  来源:igfitidea点击:

Injecting JS functions into the page from a Greasemonkey script on Chrome

javascriptgoogle-chromegoogle-chrome-extensiongreasemonkeyuserscripts

提问by Henrik Heimbuerger

I have a Greasemonkey script that works just fine in Firefox and Opera. I struggle with getting it to work in Chrome, however. The problem is injecting a function into the page that can be invoked by code from the page. Here's what I'm doing so far:

我有一个在 Firefox 和 Opera 中运行良好的 Greasemonkey 脚本。然而,我很难让它在 Chrome 中工作。问题是将一个函数注入到页面中,该函数可以被页面中的代码调用。这是我目前正在做的事情:

First, I get a helper reference to the unsafeWindowfor Firefox. This allows me to have the same code for FF and Opera (and Chrome, I thought).

首先,我得到了一个对 Firefox的unsafeWindow的帮助参考。这使我可以为 FF 和 Opera(以及 Chrome,我认为)拥有相同的代码。

var uw = (this.unsafeWindow) ? this.unsafeWindow : window;

Next, I inject a function into the page. It's really just a very thin wrapper that does nothing but invoking the corresponding function in the context of my GM script:

接下来,我将一个函数注入到页面中。它实际上只是一个非常薄的包装器,除了在我的 GM 脚本的上下文中调用相应的函数之外什么都不做:

uw.setConfigOption = function(newValue) {
    setTimeout(setConfigOption, 0, newValue);
}

Then, there's the corresponding function right in my script:

然后,我的脚本中有相应的功能:

setConfigOption = function(newValue) {
    // do something with it, e.g. store in localStorage
}

Last, I inject some HTML into the page with a link to invoke the function.

最后,我将一些 HTML 注入到页面中,并带有调用该函数的链接。

var p = document.createElement('p');
p.innerHTML = '<a href="javascript:setConfigOption(1)">set config option to 1</a>';
document.getElementById('injection-point').appendChild(p);

To summarize: In Firefox, when the user clicks that injected link, it will execute the function call on the unsafeWindow, which then triggers a timeout that invokes the corresponding function in the context of my GM script, which then does the actual processing. (Correct me if I'm wrong here.)

总结一下:在 Firefox 中,当用户单击注入的链接时,它将在 unsafeWindow 上执行函数调用,然后触发超时,在我的 GM 脚本的上下文中调用相应的函数,然后执行实际处理。(如果我在这里错了,请纠正我。)

In Chrome, I just get a "Uncaught ReferenceError: setConfigOption is not defined" error. And indeed, entering "window.setConfigOption" into the console yields an "undefined". In Firebug and the Opera developer console, the function is there.

在 Chrome 中,我只收到“未捕获的 ReferenceError:setConfigOption 未定义”错误。事实上,在控制台中输入“window.setConfigOption”会产生“未定义”。在 Firebug 和 Opera 开发人员控制台中,该功能就在那里。

Maybe there's another way to do this, but a few of my functions are invoked by a Flash object on the page, which I believe makes it necessary that I have functions in the page context.

也许还有另一种方法可以做到这一点,但我的一些函数是由页面上的 Flash 对象调用的,我相信这使得我有必要在页面上下文中拥有函数。

I took a quick look at the alternatives to unsafeWindowon the Greasemonkey wiki, but they all look pretty ugly. Am I completely on the wrong track here or should I look more closely into these?

我在 Greasemonkey wiki 上快速浏览了unsafeWindow替代方案,但它们看起来都很丑陋。我在这里完全走错了路还是应该更仔细地研究这些?

RESOLUTION:I followed Max S.' adviceand it works in both Firefox and Chrome now. Because the functions I needed to be available to the page had to call back into the regular ones, I moved my whole script to the page, i.e. it is completely wrapped into the function he called 'main()'.

解决方案:我跟随Max S。建议,它现在可以在 Firefox 和 Chrome 中使用。因为我需要在页面上可用的函数必须回调到常规函数中,所以我将整个脚本移到了页面上,即它完全包装在他称为“main()”的函数中。

To make the extra uglyness of that hack a little bit more bearable, I could at least drop the usage of unsafeWindow and wrappedJSObject now.

为了让这个 hack 的额外丑陋更容易忍受,我现在至少可以放弃使用 unsafeWindow 和wrappedJSObject。

I still haven't managed to get the content scope runnerfrom the Greasemonkey wiki working. It should do the same and it seems to execute just fine, but my functions are never accessible to <a>elements from the page, for example. I haven't yet figured out why that is.

我仍然没有设法从 Greasemonkey wiki获得内容范围运行器。它应该做同样的事情并且它似乎执行得很好,但是<a>例如,页面中的元素永远无法访问我的函数。我还没有弄清楚为什么会这样。

回答by Max Shawabkeh

The only way to communicate with the code running on the page in Chrome is through the DOM, so you'll have to use a hack like inserting a <script>tag with your code. Note that this may prove buggy if your script needs to run before everything else on the page.

在 Chrome 中与页面上运行的代码进行通信的唯一方法是通过 DOM,因此您必须使用像<script>在代码中插入标签这样的技巧。请注意,如果您的脚本需要在页面上的所有其他内容之前运行,这可能会证明存在错误。

EDIT:Here's how the Nice Alert extensiondoes this:

编辑:这是Nice Alert 扩展程序执行此操作的方式:

function main () {
  // ...
  window.alert = function() {/* ... */};
  // ...
}

var script = document.createElement('script');
script.appendChild(document.createTextNode('('+ main +')();'));
(document.body || document.head || document.documentElement).appendChild(script);

回答by Bernard Choi

I have this :

我有这个 :

contentscript.js :

内容脚本.js:

function injectJs(link) {
var scr = document.createElement('script');
scr.type="text/javascript";
scr.src=link;
document.getElementsByTagName('head')[0].appendChild(scr)
//document.body.appendChild(scr);
}

injectJs(chrome.extension.getURL('injected.js'));

injected.js :

注入.js:

function main() {
     alert('Hello World!');
}

main();

回答by NVI

I took a quick look at the alternatives to unsafeWindowon the Greasemonkey wiki, but they all look pretty ugly. Am I completely on the wrong track here or should I look more closely into these?

我在 Greasemonkey wiki 上快速浏览了unsafeWindow替代方案,但它们看起来都很丑陋。我在这里完全走错了路还是应该更仔细地研究这些?

You should look, because it's only available option. I'd prefer to use location hack.

你应该看看,因为它是唯一可用的选项。我更喜欢使用location hack

myscript.user.js:

myscript.user.js:

function myFunc(){
  alert('Hello World!');
}

location.href="javascript:(function(){" + myFunc + "})()"

example.com/mypage.html

example.com/mypage.html

<script>
myFunc() // Hello World!
</script>

Sure, it's ugly. But it's working well.

没错,就是丑。但它运作良好。



Content Scope Runner method, mentioned by Max S. is better than location hack, because its easier to debug.

Max S. 提到的 Content Scope Runner 方法比 location hack 更好,因为它更容易调试。

回答by user136036

The other answers either force you to use function expressions, import an external additional fileor use a long patched hack.

其他答案要么强制您使用函数表达式,要么导入外部附加文件,要么使用长补丁 hack

This answer will add the javascript into the page directly from your source code. It will use ECMAScript 6 (ES6) template literalsto get the multi-line javascript string effortlessly onto the page.

此答案将直接从您的源代码将 javascript 添加到页面中。它将使用 ECMAScript 6 (ES6)模板文字轻松地将多行 javascript 字符串放到页面上。

var script = document.createElement('script'); 
script.type = "text/javascript"; 
script.innerHTML = ` 
   function test() {
      alert(1);
   }
`;
document.getElementsByTagName('head')[0].appendChild(script);

Please note the backticks ``that define the beginning and the end of a multi-line string.

请注意``定义多行字符串开头和结尾的反引号。