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

IT技术 javascript google-chrome google-chrome-extension greasemonkey userscripts
2021-01-15 13:47:14

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

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

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

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

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

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

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

最后,我将一些 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);

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

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

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

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

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

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

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

4个回答

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

编辑:这是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);
@NV:run_at=document_start将 插入<script>到尚未加载的 DOM时可能会出现问题@hheimbuerger:是的,将所有代码包装到一个函数中,并用脚本插入它。
2021-03-15 13:47:14
可以通过run_at语句code.google.com/chrome/extensions/content_scripts.html定义内容脚本执行的顺序
2021-03-23 13:47:14
我尝试了“内容范围运行器”(如果我没记错的话,它就是这样做的),虽然这些功能对我的脚本可用,但它们似乎对页面不可用(例如锚标记)。您有任何示例代码或可以链接到的任何内容吗?我不是很关心执行的顺序。当我设法从页面调用注入的函数时,我可以解决这个问题。:)
2021-04-06 13:47:14
虽然您的孤立示例对我有用,但我还没有在我的完整脚本中使用它。我想,与使用 unsafeWindow 时不同,我现在无法回调直接在我的脚本中的函数。我想我必须将所有内容都移到页面上下文中。我明天试试。
2021-04-06 13:47:14
re run_at:不过,我不是在编写 Chrome 扩展程序(而且我不打算写太多工作来维护两个脚本)。这只是一个 Greasemonkey 脚本,我试图使其足够兼容,以便 Chrome 可以将 GM 脚本“自动转换”为扩展。
2021-04-10 13:47:14

我有这个 :

内容脚本.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'));

注入.js:

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

main();
这个好棒!也是使用 jQuery 的人的快捷方式:function injectjs(link) { $('<script type="text/javascript" src="'+link+'"/>').appendTo($('head')); }
2021-03-14 13:47:14

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

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

myscript.user.js:

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

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

example.com/mypage.html

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

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


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

你是什​​么意思“锚”?
2021-03-16 13:47:14
我想那也行,但我选择了 Max S。目前内容范围类似方法。谢谢你的帮助!
2021-03-25 13:47:14
myscript.user.js: location.href="javascript:(function(){window.setConfigOption=function(){ /* ... */ }})()"
2021-04-05 13:47:14
使用 <a> 标记,如在我的示例代码中,例如 <a href="javascript:setConfigOption(1)">。(我认为如果这有效,它也应该来自 Flash 对象。)
2021-04-09 13:47:14
您能否发布一个示例,说明如何使用它来定义可由锚点或 Flash 对象调用的函数?
2021-04-11 13:47:14

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

此答案将直接从您的源代码将 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);

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