Доступ к переменным из Greasemonkey на страницу и наоборот

У меня есть следующий код в test.js, который запускается прямо перед </body> :

alert('stovetop');
alert(greasy);

У меня есть следующий код в test.user.js:

(function () {

    'use strict';
    var greasy = 'greasy variable';
    document.title = 'greasy title';

}());

'stovetop' получает предупреждение, поэтому я знаю, что javascript работает, а document.title получает изменения, поэтому я знаю, что работает javascript script. Однако на веб-странице я получаю сообщение об ошибке:

Ошибка: ReferenceError: greasy не определен. Исходный файл:/test.js

Как с веб-страницы я могу получить доступ к переменной, заданной Greasemonkey, и как насчет наоборот?

Ответ 1

  • Сценарии Greasemonkey работают в отдельной области и могут также работать в песочнице, в зависимости от настроек @grant.

  • Кроме того, код вопроса изолирует greasy в области действия функции (как сказал gladoscc).

  • Наконец, по умолчанию, test.js будет запускаться раньше, чем скрипт Greasemonkey, поэтому в любом случае он не увидит никаких установленных переменных. Используйте @run-at document-start для решения этой проблемы.


Итак, учитывая этот test.js, запустите прямо перед </body>:

window.targetPages_GlobalVar = 'stovetop';

console.log ("On target page, local global: ", targetPages_GlobalVar);
console.log ("On target page, script global: ", gmScripts_GlobalVar);

Тогда будет работать следующее:

Без песочницы:

// ==UserScript==
// @name        _Greasemonkey and target page, variable interaction
// @include     http://YOUR_SERVER.COM/YOUR_PATH/*
// @include     http://output.jsbin.com/esikut/*
// @run-at      document-start
// @grant       none
// ==/UserScript==

//--- For @grant none, could also use window. instead of unsafeWindow.
unsafeWindow.gmScripts_GlobalVar = 'greasy';

console.log ("In GM script, local global: ", unsafeWindow.targetPages_GlobalVar);
console.log ("In GM script, script global: ", gmScripts_GlobalVar);

window.addEventListener ("DOMContentLoaded", function() {
    console.log ("In GM script, local global, after ready: ", unsafeWindow.targetPages_GlobalVar);
}, false);


С песочницей, без области действия, unsafeWindow:
== & GT; Важное обновление: Greasemonkeyизменил обработку unsafeWindow с версией 2.0, следующий пример сценария не будет работать с GM 2.0 или более поздней версией. Два других решения все еще работают.

// ==UserScript==
// @name        _Greasemonkey and target page, variable interaction
// @include     http://YOUR_SERVER.COM/YOUR_PATH/*
// @include     http://output.jsbin.com/esikut/*
// @run-at      document-start
// @grant    GM_addStyle
// ==/UserScript==
/*- The @grant directive is needed to work around a design change
    introduced in GM 1.0.   It restores the sandbox.
*/

unsafeWindow.gmScripts_GlobalVar = 'greasy';

console.log ("In GM script, local global: ", unsafeWindow.targetPages_GlobalVar);
console.log ("In GM script, script global: ", unsafeWindow.gmScripts_GlobalVar);

window.addEventListener ("DOMContentLoaded", function() {
    console.log ("In GM script, local global, after ready: ", unsafeWindow.targetPages_GlobalVar);
}, false);


С песочницей, без области действия, инъекция скрипта:

// ==UserScript==
// @name        _Greasemonkey and target page, variable interaction
// @include     http://YOUR_SERVER.COM/YOUR_PATH/*
// @include     http://output.jsbin.com/esikut/*
// @run-at      document-start
// @grant       GM_addStyle
// ==/UserScript==
/*- The @grant directive is needed to work around a design change
    introduced in GM 1.0.   It restores the sandbox.
*/

function GM_main () {
    window.gmScripts_GlobalVar = 'greasy';

    console.log ("In GM script, local global: ", window.targetPages_GlobalVar);
    console.log ("In GM script, script global: ", window.gmScripts_GlobalVar);

    window.addEventListener ("DOMContentLoaded", function() {
        console.log ("In GM script, local global, after ready: ", window.targetPages_GlobalVar);
    }, false);
}

addJS_Node (null, null, GM_main);

function addJS_Node (text, s_URL, funcToRun, runOnLoad) {
    var D                                   = document;
    var scriptNode                          = D.createElement ('script');
    if (runOnLoad) {
        scriptNode.addEventListener ("load", runOnLoad, false);
    }
    scriptNode.type                         = "text/javascript";
    if (text)       scriptNode.textContent  = text;
    if (s_URL)      scriptNode.src          = s_URL;
    if (funcToRun)  scriptNode.textContent  = '(' + funcToRun.toString() + ')()';

    var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
    targ.appendChild (scriptNode);
}

Примечания:

  1. Вы можете проверить эти сценарии на этой странице (output.jsbin.com/esikut/1).
  2. Без песочницы unsafeWindow и window одинаковы.
  3. Все эти скрипты выводят на консоль один и тот же вывод:

    In GM script, local global: undefined
    In GM script, script global: greasy
    On target page, local global: stovetop
    On target page, script global: greasy
    In GM script, local global, after ready: stovetop
    
  4. Код Script Injection будет работать во многих браузерах, кроме Firefox. unsafeWindow в настоящее время работает только в Firefox + Greasemonkey (или Scriptish) или Chrome + Tampermonkey.

Ответ 2

Ваша переменная greasy определена в области анонимной функции. Вы не можете получить доступ к greasy даже в своем usercript, если только он не является частью вашей функции. Пример:

(function(){
    var foo = 5;
    alert(foo);
}();
alert(foo); //ERROR, because foo is undefined outside of the function.

Сделайте это так:

var foo = 5;
(function(){
     alert(foo);
}();
alert(foo);

Кроме того, почему вы помещаете весь свой код в анонимную функцию, а затем выполняете ее?

Ответ 3

Вы также можете использовать localStorage:

localStorage.setItem("numberOfThings", "42");

localStorage.getItem("numberOfThings");