Javascript 设置@grant值时如何访问“窗口”(目标页)对象?

Javascript 设置@grant值时如何访问“窗口”(目标页)对象?,javascript,firefox,greasemonkey,Javascript,Firefox,Greasemonkey,假设我正在使用以下网页: 点击我 var hello=function(){ 警惕(“你好”); } document.getElementById('click')。addEventListener('click',函数(e){ 你好; }); 我的Greasemonkey脚本是: // ==UserScript== // @name My Script // @include http://example.com/hello.html // @version

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


点击我
var hello=function(){
警惕(“你好”);
}
document.getElementById('click')。addEventListener('click',函数(e){
你好;
});
我的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
不再针对页面上的正确对象

window.hello
替换为
unsafeWindow.hello
看起来是可行的,但是JS控制台中会抛出以下错误:

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

在将
@grant GM_setClipboard
设置为target并替换页面上原来的
hello
函数时,如何重写Greasemonkey脚本

系统信息:

  • Windows 7 64位
  • Firefox32.0
  • Greasemonkey 2.2

当您设置除none之外的
@grant
值时,Greasemonkey将激活其沙箱并启动

现在,为了在目标页面范围中创建或覆盖变量,必须从技术菜单中正确选择。例如:

全文如下:
  • 一个简单变量:

    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 }
    
    Target page sets:       function func () {console.log ('Hi');}
    GM script can call:     unsafeWindow.func() //-- "Hi"
    
    unsafeWindow.foo = "Apple";
    
    var gmObject        = {X: "123"};
    unsafeWindow.obj    = cloneInto (gmObject, unsafeWindow);
    
    function gmFunc () {
        console.log ("Lorem ipsum");
        //-- Can use GM_ functions in here! :)
    }
    unsafeWindow.func   = exportFunction (gmFunc, unsafeWindow);
    
  • 一个简单的对象:

    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 }
    
    Target page sets:       function func () {console.log ('Hi');}
    GM script can call:     unsafeWindow.func() //-- "Hi"
    
    unsafeWindow.foo = "Apple";
    
    var gmObject        = {X: "123"};
    unsafeWindow.obj    = cloneInto (gmObject, unsafeWindow);
    
    function gmFunc () {
        console.log ("Lorem ipsum");
        //-- Can use GM_ functions in here! :)
    }
    unsafeWindow.func   = exportFunction (gmFunc, unsafeWindow);
    
  • 复杂对象:这并不总是可能的

致电:
  • 一个简单的函数:

    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 }
    
    Target page sets:       function func () {console.log ('Hi');}
    GM script can call:     unsafeWindow.func() //-- "Hi"
    
    unsafeWindow.foo = "Apple";
    
    var gmObject        = {X: "123"};
    unsafeWindow.obj    = cloneInto (gmObject, unsafeWindow);
    
    function gmFunc () {
        console.log ("Lorem ipsum");
        //-- Can use GM_ functions in here! :)
    }
    unsafeWindow.func   = exportFunction (gmFunc, unsafeWindow);
    
  • 复杂函数:

要写入/设置:
  • 一个简单变量:

    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 }
    
    Target page sets:       function func () {console.log ('Hi');}
    GM script can call:     unsafeWindow.func() //-- "Hi"
    
    unsafeWindow.foo = "Apple";
    
    var gmObject        = {X: "123"};
    unsafeWindow.obj    = cloneInto (gmObject, unsafeWindow);
    
    function gmFunc () {
        console.log ("Lorem ipsum");
        //-- Can use GM_ functions in here! :)
    }
    unsafeWindow.func   = exportFunction (gmFunc, unsafeWindow);
    
  • 一个简单的对象:

    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 }
    
    Target page sets:       function func () {console.log ('Hi');}
    GM script can call:     unsafeWindow.func() //-- "Hi"
    
    unsafeWindow.foo = "Apple";
    
    var gmObject        = {X: "123"};
    unsafeWindow.obj    = cloneInto (gmObject, unsafeWindow);
    
    function gmFunc () {
        console.log ("Lorem ipsum");
        //-- Can use GM_ functions in here! :)
    }
    unsafeWindow.func   = exportFunction (gmFunc, unsafeWindow);
    
  • 一个简单的函数:

    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 }
    
    Target page sets:       function func () {console.log ('Hi');}
    GM script can call:     unsafeWindow.func() //-- "Hi"
    
    unsafeWindow.foo = "Apple";
    
    var gmObject        = {X: "123"};
    unsafeWindow.obj    = cloneInto (gmObject, unsafeWindow);
    
    function gmFunc () {
        console.log ("Lorem ipsum");
        //-- Can use GM_ functions in here! :)
    }
    unsafeWindow.func   = exportFunction (gmFunc, unsafeWindow);
    

考虑以下HTML:

<button id="helloBtn">Say "Hello".</button>
你可以在现场看到

如果在该页面上安装并运行此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."};
/==UserScript==
//@name\u演示如何访问设置了@grant值的目标页面变量
//@包括http://fiddle.jshell.net/sepwL7n6/*/展示/
//@需要http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
//@grant GM_addStyle
//==/UserScript==
console.log(“***Greasemonkey脚本开始”);
$(“body”).append('由Greasemonkey添加:

); $(“#gmArea>p:first”).append('Access select target page variables and functions'); $(“#gmArea>p:first”).append('更改目标页面范围中的javascript内容'); $(“#gmShow”)。单击(函数(){ //--从目标页面范围访问内容: console.log(“------------------------------”); console.log(“=>simpleGlobalVar为:”,unsafeWindow.simpleGlobalVar); console.log(“=>globalObject为:”,unsafeWindow.globalObject); console.log(“==>调用目标的simpleFunction():”; unsafeWindow.simpleFunction(); //--警告!下一种技术不可靠,但在某些情况下有效。 console.log(“==>调用目标按钮的click()”; unsafeWindow.document.getElementById('helloBtn')。单击(); } ); $(“#gmChange”)。单击(函数(){ this.disabled=true;//--只能单击一次。 unsafeWindow.simpleGlobalVar=“简单变量…被GM截获!”; unsafeWindow.globalObject=cloneInto(gmObject,unsafeWindow); unsafeWindow.sayHello=exportFunction(sayHello,unsafeWindow); console.log(“==>目标页面对象已更改。”); } ); var gmMessageStr=“函数…被GM截获,但也可以使用GM_u函数!”; 函数sayHello(){ sayHello.K=(sayHello.K | | 0)+1; console.log(gmMessageStr); GM_addStyle('body{background:'+(sayHello.K%2?):“white”)+';}); } var gmObject={消息:“对象被GM.覆盖”};

打开控制台并按下按钮,您将看到GM脚本能够读取和更改页面的变量和函数


注:

  • 这些都是特定于Firefox的
  • 对于跨平台代码和某些复杂情况,可以使用。但是注入的代码不能直接访问
    GM
    函数
  • 请注意,这些技术仅适用于全局javascript变量和函数

  • 将代码包装在lambda函数中,如下所示:

    (function(window){      // and more arguments if you need it
    
      console.log(window);  // here, should be the real 'window'
    
    })(window.unsafeWindow)
    

    你可能想看看新的
    unsafeWindow
    行为是否真的来自Firefox30,就像它在中所说的那样?据推测,GM 2.0中的相关更改与确保新API可供GM脚本使用有关,并且可能是GM自己正确地使用了这些API,而不是依赖于旧的行为。@SamB,不完全如此。请注意,该博客条目是关于SDK的,而不是关于Firefox的。通用汽车不使用SDK,也不必进行当时所做的更改。目前尚不清楚未来计划对FF的更改是否最终会迫使进行更改,但新方法更好,因为它允许更容易地将GM功能集成到目标页面代码中(这是一种危险的做法)。