如何设置@grant值时如何访问`window`(目标页面)对象?

假设我正在使用以下网页:

<html> <body> <span id="click">click me</span> <script> var hello = function() { alert('hello'); } document.getElementById('click').addEventListener('click', function(e) { hello(); }); </script> </body> </html> 

我的Greasemonkey脚本是:

 // ==UserScript== // @name My Script // @include http://example.com/hello.html // @version 1 // @grant none // ==/UserScript== window.hello = function() { alert('goodbye'); } 

在禁用Greasemonkey脚本的情况下,单击页面上的#click元素将显示“hello”警报。 启用脚本后,单击该元素将显示“再见”警报。

很简单。 来自网页的hello函数正在被Greasemonkey脚本中的函数取代。

现在让我们说我想使用Greasemonkey API。 当我将@grant值设置为“none”以外的有效值(例如// @grant GM_setClipboard )[这会导致Greasemonkey将脚本作为“内容脚本”运行,而不是像'none'一样在页面范围内运行],Greasemonkey脚本无法工作。

window.hello不再针对页面上的正确对象。

unsafeWindow.helloreplacewindow.hello看起来好像会起作用,但是在JS控制台中引发下面的错误:

错误:拒绝访问对象的权限

如何在将@grant GM_setClipboard设置为target并replace页面上的原始hello函数的同时重写Greasemonkey脚本?

系统信息:

  • Windows 7 64位
  • Firefox 32.0
  • Greasemonkey 2.2

当你设置一个@grant值而不是none时,Greasemonkey激活它的沙箱, Greasemonkey 2.0从根本上改变了unsafeWindow处理 。

现在,为了在目标页面范围中创build或覆盖variables,您必须从技术菜单中正确select。 例如:

读书:

  • 一个简单的variables:

     Target page sets: var foo = "bar"; GM script can read: unsafeWindow.foo //-- "bar" 
  • 一个简单的对象:

     Target page sets: var obj = {A: 1}; GM script can read: unsafeWindow.obj //-- Object { A: 1 } 
  • 一个复杂的对象:这并不总是可能的。

致电:

  • 一个简单的function:

     Target page sets: function func () {console.log ('Hi');} GM script can call: unsafeWindow.func() //-- "Hi" 
  • 一个复杂的function: 这并不总是可能的。

写/设置:

  • 一个简单的variables:

     unsafeWindow.foo = "Apple"; 
  • 一个简单的对象:

     var gmObject = {X: "123"}; unsafeWindow.obj = cloneInto (gmObject, unsafeWindow); 
  • 一个简单的function:

     function gmFunc () { console.log ("Lorem ipsum"); //-- Can use GM_ functions in here! :) } unsafeWindow.func = exportFunction (gmFunc, unsafeWindow); 

考虑这个HTML:

 <button id="helloBtn">Say "Hello".</button> 

而这个javascript:

 var simpleGlobalVar = "A simple, global var in the page scope."; var globalObject = {Letter: "A", Number: 2}; function simpleFunction () { console.log ("The target page's simpleFunction was called."); } var sayHello = function() { console.log ('Hello.'); } document.getElementById ('helloBtn').addEventListener ('click', function () { sayHello (); } ); 

你可以在这个jsFiddle页面上看到现场。

如果你在这个页面上安装并运行这个Greasemonkey脚本:

 // ==UserScript== // @name _Demonstrate accessing target-page variables with @grant values set // @include http://fiddle.jshell.net/sepwL7n6/*/show/ // @require http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js // @grant GM_addStyle // ==/UserScript== console.log ("*** Greasemonkey script start."); $("body").append ('<div id="gmArea">Added by Greasemonkey:<p></p></div>'); $("#gmArea > p:first").append ('<button id="gmShow">Access select target-page variables and functions</button>'); $("#gmArea > p:first").append ('<button id="gmChange">Change javascript things in the target-page scope.</button>'); $("#gmShow").click ( function () { //-- Access things from the target-page scope: console.log ("----------------"); console.log ("==> simpleGlobalVar is: ", unsafeWindow.simpleGlobalVar); console.log ("==> globalObject is: ", unsafeWindow.globalObject); console.log ("==> Calling target's simpleFunction():"); unsafeWindow.simpleFunction (); //-- WARNING! This next technique is not robust, but works in some cases. console.log ("==> Calling target's button's click()."); unsafeWindow.document.getElementById ('helloBtn').click (); } ); $("#gmChange").click ( function () { this.disabled = true; //-- Can only click once. unsafeWindow.simpleGlobalVar = "Simple var... Intercepted by GM!"; unsafeWindow.globalObject = cloneInto (gmObject, unsafeWindow); unsafeWindow.sayHello = exportFunction (sayHello, unsafeWindow); console.log ("==> Target page objects were changed."); } ); var gmMessageStr = "Function... Intercepted by GM, but also can use GM_ functions!"; function sayHello () { sayHello.K = (sayHello.K || 0) + 1; console.log (gmMessageStr); GM_addStyle ('body {background: ' + (sayHello.K % 2 ? "lime" : "white") + ';}'); } var gmObject = {message: "Object overridden by GM."}; 

打开控制台并按下button,您将看到GM脚本能够读取和更改页面的variables和function。


笔记:

  1. 这是所有Firefox特定的
  2. 对于跨平台代码和一些复杂的情况,您可以使用Script Injection代替。 但是注入的代码不能直接访问GM_函数。
  3. 请注意,这些技术仅适用于全局的JavaScriptvariables和函数。