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

时间:2010-02-20 18:20:29

标签: javascript google-chrome google-chrome-extension greasemonkey userscripts

我有一个Greasemonkey脚本,在Firefox和Opera中运行良好。但是,我很难让它在Chrome中运行。问题是在页面中注入一个可以通过页面中的代码调用的函数。以下是我到目前为止所做的事情:

首先,我获得了Firefox unsafeWindow的帮助引用。这允许我为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上的alternatives to unsafeWindow,但它们看起来都非常难看。我在这里完全走错了轨道还是应该仔细研究这些?

解决方法:我关注Max S.' advice,现在可以在Firefox和Chrome中使用。因为我需要在页面上使用的函数必须回调常规函数,所以我将整个脚本移动到页面,即它完全包含在他称为“main()”的函数中。

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

我仍然无法从Greasemonkey wiki中获得content scope runner。它应该做同样的事情似乎执行得很好,但是我的函数永远不会被页面中的<a>元素访问,例如。我还没弄清楚为什么会这样。

4 个答案:

答案 0 :(得分:67)

与Chrome中页面上运行的代码进行通信的唯一方法是通过DOM,因此您必须使用hack,例如在代码中插入<script>标记。请注意,如果您的脚本需要在页面上的其他所有内容之前运行,则可能会出现问题。

编辑:以下是the Nice Alert extension执行此操作的方式:

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

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

答案 1 :(得分:15)

我有这个:

contentscript.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'));

inject.js:

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

main();

答案 2 :(得分:4)

  

我快速浏览了Greasemonkey wiki上的alternatives to 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.提到的内容范围运行器方法比位置黑客更好,因为它更容易调试。

答案 3 :(得分:2)

其他答案会强制您使用function expressions,导入external additional file或使用long patched hack

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

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

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