36

我有一个Greasemonkey脚本,可以在Firefox和Opera中正常工作。然而,我努力让它在Chrome中运行。问题是将一个函数注入到页面中的代码可以调用的页面中。这是我到目前为止所做的:在Chrome上从Greasemonkey脚本将JS函数注入页面

首先,我得到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()”的函数中。

为了让这种黑客变得更加尴尬,我现在至少可以放弃使用unsafeWindow和wrappedJSObject。

我还没有设法让Greasemonkey wiki上的content scope runner正常工作。它应该做同样的事情,它似乎执行得很好,但我的功能从不可访问页面中的<a>元素,例如。我还没有弄清楚为什么。

回答

58

与Chrome上的页面上运行的代码进行通信的唯一方法是通过DOM,因此您必须使用黑客,如在代码中插入<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

我试过'content scope runner'(如果我没有弄错的话,确实如此),并且当函数可用于我的脚本时,它们似乎不可用于页面(例如锚标签)。你有任何示例代码或任何你可以链接到? 我并不十分在意执行的顺序。当我设法从页面调用一个注入函数时,我可以解决这个问题。 :) – 2010-02-20 19:37:41

+0

内容脚本执行的顺序可以通过'run_at'语句来定义http://code.google.com/chrome/extensions/content_scripts.html – NVI 2010-02-20 20:27:24

+0

re run_at:我没有写一个Chrome扩展,尽管(和我不打算过多地维护两个脚本)。这只是一个Greasemonkey脚本,我试图做足够的兼容性,以便Chrome可以将GM脚本“自动转换”为扩展名。 – 2010-02-20 20:32:25

4

I took a quick look at the alternatives to unsafeWindow on 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?

你应该看看,因为它是唯一可用的选项。我宁愿使用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.提到的Runner方法比位置hack更好,因为它更易于调试。

+0

请问您可以发表一个如何用来定义一个可以被锚点或Flash对象调用的函数的例子吗? – 2010-02-20 19:34:05

+0

你是什么意思“由主播”? – NVI 2010-02-20 20:16:06

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

injected.js:

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

main(); 
+2

这是一个伟大的!对于使用jQuery的人来说也是快捷方式: 'function injectjs(link){0} {script type =“text/javascript”src =''+ link +'“/>')。appendTo($('head')) ; }' – 2012-03-29 00:09:25

0

其他的答案要么强迫你使用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); 

请注意,定义开始和一个多行字符串末尾的反引号``

相关问题