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

請注意,定義開始和一個多行字符串末尾的反引號``

相關問題