Как я могу использовать jQuery в скриптах Greasemonkey в Google Chrome?

Как некоторые из вас, возможно, знают, Google Chrome наложил серьезные ограничения на скрипты Greasemonkey.

Chromium не поддерживает @require, @resource, unsafeWindow, GM_registerMenuCommand, GM_setValue или GM_getValue.

Без необходимости я не могу найти способ включить библиотеку jQuery в скрипт Greasemonkey в Google Chrome.

Есть ли у кого-нибудь совет по этому поводу?


person Alekc    schedule 11.02.2010    source источник
comment
Стоит отметить, что Google Chrome с Tampermonkey теперь поддерживает @require, что является гораздо более простым подходом, чем те, что указаны в ответах.   -  person Steen Schütt    schedule 06.06.2013
comment
Tampermonkey также поддерживает unsafeWindow, что очень удобно для страниц, на которых уже есть jQuery. var $ = unsafeWindow.jQuery;   -  person Tim Goodman    schedule 09.10.2013
comment
@require отлично работает на сайтах, где вас не беспокоит конфликт с какой-либо из тысяч или миллионов других JS-библиотек, которые привязываются к $ при загрузке. Однако, если вы пишете сценарий для сайта, используя $ для чего-то еще, или, что еще хуже, пишете сценарий для запуска на всех сайтах, используйте сравнительно безопасный механизм загрузки, описанный ниже в tghw.   -  person GDorn    schedule 10.11.2016


Ответы (11)


Из " Совет по пользовательскому сценарию: использование jQuery - блог Эрика Волда "

// ==UserScript==
// @name         jQuery For Chrome (A Cross Browser Example)
// @namespace    jQueryForChromeExample
// @include      *
// @author       Erik Vergobbi Vold & Tyler G. Hicks-Wright
// @description  This userscript is meant to be an example on how to use jQuery in a userscript on Google Chrome.
// ==/UserScript==

// a function that loads jQuery and calls a callback function when jQuery has finished loading
function addJQuery(callback) {
  var script = document.createElement("script");
  script.setAttribute("src", "//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js");
  script.addEventListener('load', function() {
    var script = document.createElement("script");
    script.textContent = "window.jQ=jQuery.noConflict(true);(" + callback.toString() + ")();";
    document.body.appendChild(script);
  }, false);
  document.body.appendChild(script);
}

// the guts of this userscript
function main() {
  // Note, jQ replaces $ to avoid conflicts.
  alert("There are " + jQ('a').length + " links on this page.");
}

// load jQuery and execute the main function
addJQuery(main);
person tghw    schedule 23.08.2010
comment
Вместо трех строк внутри addEventListener для 'load' не будет callback (); просто работай? - person crdx; 10.07.2011
comment
Я не совсем уверен, но я считаю, что это связано с тем, как хром разделяет расширения и веб-страницы. Если бы он был просто вызван в сценарии, он бы выполнялся в контексте расширения, а не на странице, поэтому у вас не было бы доступа ни к чему. - person tghw; 17.08.2011
comment
Моя страница уже включает jQuery, но кажется, что приведенный выше код все еще необходим для использования jQuery в пользовательском скрипте. Однако два включения jQuery могут вызвать конфликт, поэтому первая строка вашей функции main () может быть jQuery.noConflict (); - person slolife; 10.09.2011
comment
Могу ли я импортировать несколько внешних JS-библиотек в один пользовательский скрипт с помощью этого метода? - person Isuru; 30.12.2011
comment
эпический метод! Благодарность! но не используйте 1.4.2! напишите 1, и он вернет последний jquery - person puchu; 08.01.2012
comment
Я изменил строку script.textContent = "(" + callback.toString() + ")();"; на script.textContent = "jQuery.noConflict();(" + callback.toString() + ")();"; в моем собственном шаблоне пользовательского скрипта, чтобы не было никаких неожиданных конфликтов. :) - person RCE; 30.01.2012
comment
Не сразу очевидно, как изменить этот код, чтобы добавить jQuery UI, а также сам jQuery) -: - person hippietrail; 13.06.2012
comment
@hippietrail В main() вы можете использовать $.loadScript(), а затем запустить все остальное, когда loadScript завершит загрузку jQueryUI. - person tghw; 19.06.2012
comment
Прекрасно работает. Используйте //code.jquery.com/jquery-latest.min.js в качестве источника скрипта. Относится к последнему скрипту, и его не волнует, используете ли вы http или https. - person Germstorm; 13.07.2012
comment
Похоже, в этом коде присутствует какое-то состояние гонки. Когда я использую его на StackExchange, он регулярно (но не всегда) предотвращает появление панели инструментов и предварительного просмотра при редактировании сообщений. (Это под Windows 7 Starter на нетбуке.) - person hippietrail; 23.09.2012
comment
@MichaelS. Я могу подтвердить, что он все еще работает. Вам просто нужно перетащить файл foo.user.js на страницу расширений, чтобы установить / переустановить его. - person tghw; 25.01.2013
comment
Спасибо, что поделились - я загрузил пример скрипта greasemonkey на gist: gist.github.com/netsi1964/4721303 - person Netsi1964; 06.02.2013
comment
tghw вы правы, он все еще работает. Пользовательский скрипт, работающий в Facebook, не работает. Ошибка: отказался загрузить скрипт ajax.googleapis. com / ajax / libs / jquery / 1 / jquery.min.js ', поскольку он нарушает следующую директиву политики безопасности контента: script-src https: //*.facebook.com http: //*.facebook. com https: //*.fbcdn.net http: //*.fbcdn.net .facebook.net * .google-analytics.com * .virtualearth.net * .google.com 127.0.0.1: .spotilocal.com: chrome-extension: // lifbcibllhkdhoafpjfnlhfpfgnpldfl 'unsafe-inline' unsafe-eval 'https: //*.akamaihd.net http: //*.akamaihd.net. - person Michael S.; 09.02.2013
comment
Похоже, это характерно и для Facebook в Chrome. Если у кого-то есть работа, не вставляя весь код jquery min, это было бы очень признательно. - person Michael S.; 09.02.2013
comment
@MichaelS. Откройте новый вопрос. Там будет легче ответить. - person tghw; 09.02.2013
comment
-1: с помощью этого метода код в main будет выполняться в контексте целевой страницы, что означает, что (среди прочего) применяется политика межсайтовых запросов целевой страницы (например, мне пришлось повторно внедрить GM_xmlhttpRequest, прежде чем я увидел это мне это не помогло). В конце концов я просто скопировал вставленный код jquery.min.js. - person Jean Hominal; 16.03.2013
comment
@JeanHominal Это правда, это не сработает для некоторых сайтов, если они заблокируют это. Но, помимо помещения всего jquery в скрипт, это единственный способ сделать это. - person tghw; 16.03.2013
comment
Что ж, это также стало важным для меня, потому что я хотел выполнить межсайтовый XML HTTP-запрос, и я был озадачен тем, что политика межсайтового скриптинга Chrome все еще блокирует меня (и даже выполнение этого в TamperMonkey не решило этого!), Пока Я понял, что Chrome применил ко мне политику межсайтового скриптинга хост-сайта, потому что скрипт действительно выполнялся в этом контексте. - person Jean Hominal; 17.03.2013

Я написал несколько функций на основе Сценарий Эрика Волда, который помогает мне запускать функции, код и другие сценарии в документе. Вы можете использовать их для загрузки jQuery на страницу и последующего запуска кода в глобальной области window.

Пример использования

// ==UserScript==
// @name           Example from http://stackoverflow.com/q/6834930
// @version        1.3
// @namespace      http://stackoverflow.com/q/6834930
// @description    An example, adding a border to a post on Stack Overflow.
// @include        http://stackoverflow.com/questions/2246901/*
// ==/UserScript==

var load,execute,loadAndExecute;load=function(a,b,c){var d;d=document.createElement("script"),d.setAttribute("src",a),b!=null&&d.addEventListener("load",b),c!=null&&d.addEventListener("error",c),document.body.appendChild(d);return d},execute=function(a){var b,c;typeof a=="function"?b="("+a+")();":b=a,c=document.createElement("script"),c.textContent=b,document.body.appendChild(c);return c},loadAndExecute=function(a,b){return load(a,function(){return execute(b)})};

loadAndExecute("//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js", function() {
    $("#answer-6834930").css("border", ".5em solid black");
});

Вы можете щелкнуть здесь, чтобы установить его, если доверяете что я не пытаюсь обманом заставить вас установить что-то вредоносное, и что никто не редактировал мой пост, чтобы указать на что-то еще. Перезагрузите страницу, и вы увидите рамку вокруг моего сообщения.

Функции

load(url, onLoad, onError)

Загружает сценарий по адресу url в документ. По желанию, обратные вызовы могут быть предоставлены для onLoad и onError.

execute(functionOrCode)

Вставляет функцию или строку кода в документ и выполняет ее. Перед вставкой функции преобразуются в исходный код, поэтому они теряют свою текущую область действия / закрытие и выполняются в глобальной области window.

loadAndExecute(url, functionOrCode)

Ярлык; это загружает сценарий из url, затем вставляет и выполняет functionOrCode в случае успеха.

Код

function load(url, onLoad, onError) {
    e = document.createElement("script");
    e.setAttribute("src", url);

    if (onLoad != null) { e.addEventListener("load", onLoad); }
    if (onError != null) { e.addEventListener("error", onError); }

    document.body.appendChild(e);

    return e;
}

function execute(functionOrCode) {
    if (typeof functionOrCode === "function") {
        code = "(" + functionOrCode + ")();";
    } else {
        code = functionOrCode;
    }

    e = document.createElement("script");
    e.textContent = code;

    document.body.appendChild(e);

    return e;
}

function loadAndExecute(url, functionOrCode) {
    load(url, function() { execute(functionOrCode); });
}
person Jeremy    schedule 26.07.2011
comment
@cyphunk Да, для меня было очень важно спасти этих нескольких персонажей. На самом деле, я чувствую себя довольно глупо из-за того, что оставил этот пост, используя его так бессмысленно. Я сниму. - person Jeremy; 04.10.2012

Используйте jQuery не опасаясь конфликтов, вызвав jQuery.noConflict(true). Вот так:

function GM_main ($) {
    alert ('jQuery is installed with no conflicts! The version is: ' + $.fn.jquery);
}

add_jQuery (GM_main, "1.7.2");

function add_jQuery (callbackFn, jqVersion) {
    jqVersion       = jqVersion || "1.7.2";
    var D           = document;
    var targ        = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
    var scriptNode  = D.createElement ('script');
    scriptNode.src  = 'http://ajax.googleapis.com/ajax/libs/jquery/'
                    + jqVersion
                    + '/jquery.min.js'
                    ;
    scriptNode.addEventListener ("load", function () {
        var scriptNode          = D.createElement ("script");
        scriptNode.textContent  =
            'var gm_jQuery  = jQuery.noConflict (true);\n'
            + '(' + callbackFn.toString () + ')(gm_jQuery);'
        ;
        targ.appendChild (scriptNode);
    }, false);
    targ.appendChild (scriptNode);
}


Но, Для кроссбраузерных скриптов, почему бы не воспользоваться хорошей, быстрой локальной копией jQuery, когда это возможно?

Следующее работает как пользовательский скрипт Chrome и скрипт Greasemonkey, и он использует красивую локальную @require копию jQuery, если платформа поддерживает это.

// ==UserScript==
// @name     _Smart, cross-browser jquery-using script
// @include  http://YOUR_SERVER.COM/YOUR_PATH/*
// @require  http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @grant    GM_info
// ==/UserScript==

function GM_main ($) {
    alert ('jQuery is installed with no conflicts! The version is: ' + $.fn.jquery);
}

if (typeof jQuery === "function") {
    console.log ("Running with local copy of jQuery!");
    GM_main (jQuery);
}
else {
    console.log ("fetching jQuery from some 3rd-party server.");
    add_jQuery (GM_main, "1.7.2");
}

function add_jQuery (callbackFn, jqVersion) {
    var jqVersion   = jqVersion || "1.7.2";
    var D           = document;
    var targ        = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
    var scriptNode  = D.createElement ('script');
    scriptNode.src  = 'http://ajax.googleapis.com/ajax/libs/jquery/'
                    + jqVersion
                    + '/jquery.min.js'
                    ;
    scriptNode.addEventListener ("load", function () {
        var scriptNode          = D.createElement ("script");
        scriptNode.textContent  =
            'var gm_jQuery  = jQuery.noConflict (true);\n'
            + '(' + callbackFn.toString () + ')(gm_jQuery);'
        ;
        targ.appendChild (scriptNode);
    }, false);
    targ.appendChild (scriptNode);
}
person Brock Adams    schedule 05.10.2012
comment
+1 Впечатляет, из всех этих ответов ваш единственный, в котором говорится об использовании @require, вы также можете использовать $ = unsafeWindow.jQuery, если на странице есть jQuery (я тестировал это только в Tampermonkey). - person A.M.K; 21.11.2012
comment
Предостережение: в некоторых версиях IE нет console.log (), если вы не установили инструменты разработчика, поэтому скрипт выйдет из строя. Обычно вы обнаруживаете это только после того, как выпустите свой скрипт, помимо разработчиков и специалистов по контролю качества. - person Parsingphase; 28.05.2013
comment
@Parsingphase, IE здесь в значительной степени NA. Последний раз я проверял, IE по-прежнему плохо поддерживает пользовательские скрипты (¿вообще?). Изменилось ли это в IE 10? - person Brock Adams; 28.05.2013
comment
Брок - хороший момент, я не могу держать в голове матрицу несовместимости IE. Таким образом, это напрямую не применимо к пользовательским скриптам (хотя кажется, что люди иногда пытаются реализовать решение IE), а скорее общая проблема. - person Parsingphase; 03.06.2013

Если на странице уже есть jQuery, просто следуйте этому шаблону:

// ==UserScript==
// @name          My Script
// @namespace     my-script
// @description   Blah
// @version       1.0
// @include       http://site.com/*
// @author        Me
// ==/UserScript==

var main = function () {

    // use $ or jQuery here, however the page is using it

};

// Inject our main script
var script = document.createElement('script');
script.type = "text/javascript";
script.textContent = '(' + main.toString() + ')();';
document.body.appendChild(script);
person Mottie    schedule 17.01.2012
comment
Я не думаю, что это работает, потому что у пользовательского скрипта нет доступа к окну документов? - person Christoph; 16.11.2012
comment
@Christoph Это действительно работает, у меня есть и я все еще использую пользовательский скрипт, используя этот метод. - person Mottie; 16.11.2012
comment
Фактически это внедрение скрипта greasemonkey на страницу. Так что, вероятно, обходит некоторые меры безопасности, которые есть у greasemonkey. - person Thymine; 22.01.2013
comment
@Thymine Я заметил, что этот метод вводит пользовательский скрипт на нежелательные страницы. Мне пришлось заключить часть инъекции в оператор if, который проверяет window.location. - person Mottie; 22.01.2013

Самый простой способ - использовать ключевое слово required:

// @require     http://code.jquery.com/jquery-latest.js
person Stiger    schedule 28.07.2014
comment
Поддерживается только реализацией расширения. - person user2284570; 15.12.2014
comment
@ user2284570 Он поддерживается всеми расширениями пользовательских скриптов, которые я смог найти для любого браузера. - person Mattwmaster58; 03.04.2018
comment
@MattM. Я имею в виду, что вам не нужно устанавливать расширение в Opera и Chrome для запуска пользовательских скриптов. - person user2284570; 04.04.2018

Есть действительно простой способ обойтись, включая полную копию сценариев jQuery для Chrome , когда эти сценарии фактически не используют никаких привилегированных функций (функции GM_ * и т. Д.) ...

Просто вставьте сам скрипт в DOM страницы и выполните! Самое приятное то, что этот метод работает так же хорошо в Firefox + Greasemonkey, поэтому вы можете использовать один и тот же скрипт для обоих:

var script = document.createElement("script");
script.type = "text/javascript";
script.textContent = "(" + threadComments.toString() + ")(jQuery)";
document.body.appendChild(script);

function threadComments($) {
    // taken from kip's http://userscripts-mirror.org/scripts/review/62163
    var goodletters = Array('\u00c0','\u00c1','\u00c2','\u00c3','\u00c4','\u00c5','\u00c6','\u00c7'
                             ,'\u00c8','\u00c9','\u00ca','\u00cb','\u00cc','\u00cd','\u00ce','\u00cf'
                                      ,'\u00d1','\u00d2','\u00d3','\u00d4','\u00d5','\u00d6'         
                             ,'\u00d8','\u00d9','\u00da','\u00db','\u00dc','\u00dd'                  
                             ,'\u00e0','\u00e1','\u00e2','\u00e3','\u00e4','\u00e5','\u00e6','\u00e7'
                             ,'\u00e8','\u00e9','\u00ea','\u00eb','\u00ec','\u00ed','\u00ee','\u00ef'
                                      ,'\u00f1','\u00f2','\u00f3','\u00f4','\u00f5','\u00f6'         
                             ,'\u00f8','\u00f9','\u00fa','\u00fb','\u00fc','\u00fd'         ,'\u00ff').join('');

    // from Benjamin Dumke's http://userscripts-mirror.org/scripts/review/68252
    function goodify(s)
      {
         good = new RegExp("^[" + goodletters + "\\w]{3}");
         bad = new RegExp("[^" + goodletters + "\\w]");
         original = s;
         while (s.length >3 && !s.match(good)) {
            s = s.replace(bad, "");
            }
         if (!s.match(good))
         {
           // failed, so we might as well use the original
           s = original;
         }
         return s;
      }  

    in_reply_to = {};


    function who(c, other_way) {


        if (other_way)
        {
            // this is closer to the real @-reply heuristics
            m = /@(\S+)/.exec(c);
        }
        else
        {
            m = /@([^ .:!?,()[\]{}]+)/.exec(c);
        }
        if (!m) {return}
        if (other_way) {return goodify(m[1]).toLowerCase().slice(0,3);}
        else {return m[1].toLowerCase().slice(0,3);}
    }

    function matcher(user, other_way) {
        if (other_way)
        {
            return function () {
                return goodify($(this).find(".comment-user").text()).toLowerCase().slice(0,3) == user
                }
        }
        else
        {
            return function () {
                return $(this).find(".comment-user").text().toLowerCase().slice(0,3) == user
                }
        }
    }

    function replyfilter(id) {
        return function() {
            return in_reply_to[$(this).attr("id")] == id;
        }
    }

    function find_reference() {
        comment_text = $(this).find(".comment-text").text();
        if (who(comment_text))
        {
            fil = matcher(who(comment_text));
            all = $(this).prevAll("tr.comment").filter(fil);
            if (all.length == 0)
            {
                // no name matched, let's try harder
                fil = matcher(who(comment_text, true), true);
                all = $(this).prevAll("tr.comment").filter(fil);
                if (all.length == 0) {return}
            }
            reference_id = all.eq(0).attr("id");
            in_reply_to[$(this).attr("id")] = reference_id;
        }
    }


    // How far may comments be indented?
    // Note that MAX_NESTING = 3 means there are
    // up to *four* levels (including top-level)
    MAX_NESTING = 3

    // How many pixels of indentation per level?
    INDENT = 30

    function indenter(parent) {

        for (var i = MAX_NESTING; i > 0; i--)
        {
            if (parent.hasClass("threading-" + (i-1)) || (i == MAX_NESTING && parent.hasClass("threading-" + i)))
            {
                return function() {
                    $(this).addClass("threading-" + i).find(".comment-text").css({"padding-left": INDENT*i});
                }
            }
        }

        return function() {
            $(this).addClass("threading-1").find(".comment-text").css({"padding-left": INDENT});
        }

    }

    function do_threading(){
        id = $(this).attr("id");
        replies = $(this).nextAll("tr.comment").filter(replyfilter(id));
        ind = indenter($(this));
        replies.each(ind);
        replies.insertAfter(this);
    }

    function go() {
        $("tr.comment").each(find_reference);
        $("tr.comment").each(do_threading);
    }

    $.ajaxSetup({complete: go});
    go();
}

(без извинений украдено у Shog9 на meta.stackoverflow, поскольку он не перемещал его сюда, и я должен удалить мета-сообщение ..)

person Community    schedule 18.02.2011

Кроме того, вы можете упаковать свой скрипт с расширением jQuery для Chrome. См. Скрипты содержания Google Chrome.

Расширения Chrome, в отличие от скриптов Greasemonkey, могут автоматически обновляться.

person NVI    schedule 16.02.2010
comment
да, было бы проще. Но я действительно предпочитаю пока поддерживать свой скрипт через userscripts.org, а не создавать избыточность с помощью репозитория расширений Google. - person Alekc; 17.02.2010
comment
И его загрузка в Google Web Store стоит 5 долларов. - person Camilo Martin; 23.02.2012

Более простое решение: вырезать + вставить содержимое jquery.min.js в верхнюю часть пользовательского скрипта. Сделанный.

Я обнаружил различные проблемы с рекомендованными ответами. Решение addJQuery () работает на большинстве страниц, но на многих есть ошибки. Если у вас возникнут проблемы, просто скопируйте + вставьте содержимое jquery в свой скрипт.

person cyphunk    schedule 04.10.2012
comment
Да, я думаю, что в этом есть смысл, потому что можно даже написать небольшой скрипт сборки, который генерирует хром-версию, делая именно то, что вы предлагаете здесь. - person dkinzer; 20.08.2013

Интересно, не могли бы вы положиться на document.defaultView.jQuery в своем скрипте GM аля:

if (document.defaultView.jQuery) {
  jQueryLoaded(document.defaultView.jQuery);
} else {
  var jq = document.createElement('script');
  jq.src = 'http://jquery.com/src/jquery-latest.js';
  jq.type = 'text/javascript';
  document.getElementsByTagName('head')[0].appendChild(jq);
  (function() { 
    if (document.defaultView.jQuery) jQueryLoaded(document.defaultView.jQuery);
    else setTimeout(arguments.callee, 100);
  })();
}

function jQueryLoaded($) {
  console.dir($);
}
person gnarf    schedule 22.07.2010

Другой подход - изменить ваш скрипт для загрузки jQuery вручную. Пример из http://joanpiedra.com/jquery/greasemonkey/:

// Add jQuery
var GM_JQ = document.createElement('script');
GM_JQ.src = 'http://jquery.com/src/jquery-latest.js';
GM_JQ.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(GM_JQ);

// Check if jQuery's loaded
function GM_wait() {
    if(typeof unsafeWindow.jQuery == 'undefined') { window.setTimeout(GM_wait,100); }
else { $ = unsafeWindow.jQuery; letsJQuery(); }
}
GM_wait();

// All your GM code must be inside this function
function letsJQuery() {
    alert($); // check if the dollar (jquery) function works
}

РЕДАКТИРОВАТЬ: DRATS! После тестирования выяснилось, что этот код не работает, поскольку Google Chrome запускает пользовательские скрипты / расширения в отдельной области / процессе, отличной от реальной веб-страницы. Вы можете загрузить код jQuery с помощью XmlhttpRequest, а затем Eval, но вы должны разместить код на сервере, который позволяет Совместное использование ресурсов между источниками с использованием заголовка Access-Control-Allow-Origin: *. К сожалению, НИ ОДИН из текущих CDN с jQuery не поддерживает это.

person Greg Bray    schedule 12.04.2010

Идеальное расширение для встраивания jQuery в консоль Chrome так просто, как вы можете себе представить. Это расширение также указывает, был ли jQuery уже встроен в страницу.

Это расширение используется для встраивания jQuery на любую страницу, которую вы хотите. Это позволяет использовать jQuery в оболочке консоли (вы можете вызвать консоль Chrome с помощью «Ctrl + Shift + j»).

Чтобы встроить jQuery в выбранную вкладку, нажмите кнопку расширения.

ССЫЛКА на расширение: https://chrome.google.com/extensions/detail/gbmifchmngifmadobkdetail/gbmifchmngifmadobkdetail/gbmifchmngifmadobkdeecp >

person Andrey    schedule 22.07.2010
comment
На самом деле это не ответ. И зачем мне загружать jQuery, если мне это не нужно? - person Vik; 28.07.2015