如何在 Google Chrome 的 Greasemonkey 脚本中使用 jQuery?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2246901/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 13:06:44  来源:igfitidea点击:

How can I use jQuery in Greasemonkey scripts in Google Chrome?

jquerygoogle-chromegreasemonkeyrequireuserscripts

提问by Alekc

As some of you may know, Google Chrome has put some severe limitation on Greasemonkey scripts.

你们中的一些人可能知道,谷歌浏览器对 Greasemonkey 脚本施加了一些严格的限制。

Chromium does not support @require, @resource, unsafeWindow, GM_registerMenuCommand, GM_setValue, or GM_getValue.

铬不支持@require@resourceunsafeWindowGM_registerMenuCommandGM_setValue,或GM_getValue

Without require, I can't find a way to include the jQuery library in Greasemonkey script under Google Chrome.

没有要求,我找不到在 Google Chrome 下的 Greasemonkey 脚本中包含 jQuery 库的方法。

Does anybody have some advice in this matter?

有人对这件事有什么建议吗?

回答by tghw

From "User Script Tip: Using jQuery - Erik Vold's Blog"

来自“用户脚本提示:使用 jQuery - Erik Vold 的博客”

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

回答by Facebook Staff are Complicit

I have written a few functions based on the Erik Vold's scriptto help run me run functions, code and other scripts in a document. You can use them to load jQuery into the page and then run code under the global windowscope.

我已经根据Erik Vold 的脚本编写了一些函数来帮助我运行文档中的函数、代码和其他脚本。您可以使用它们将 jQuery 加载到页面中,然后在全局window范围内运行代码。

Example Usage

示例用法

// ==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");
});

You can click hereto install it, if you trust that I'm not trying to trick you into installing something malicious and that nobody has edited my post to point to something else. Reload the page and you should see a border around my post.

您可以单击此处安装它,如果您相信我不会试图诱骗您安装恶意软件,并且没有人编辑过我的帖子以指向其他内容。重新加载页面,您应该会在我的帖子周围看到一个边框。

Functions

职能

load(url, onLoad, onError)

load(url, onLoad, onError)

Loads the script at urlinto the document. Optionally, callbacks may be provided for onLoadand onError.

将脚本加载url到文档中。可选地,可以为onLoad和提供回调onError

execute(functionOrCode)

execute(functionOrCode)

Inserts a function or string of code into the document and executes it. The functions are converted to source code before being inserted, so they lose their current scope/closures and are run underneath the global windowscope.

将函数或代码字符串插入文档并执行它。这些函数在插入之前被转换为源代码,因此它们失去了当前的作用域/闭包并在全局window作用域下运行。

loadAndExecute(url, functionOrCode)

loadAndExecute(url, functionOrCode)

A shortcut; this loads a script from url, then inserts and executes functionOrCodeif successful.

一条捷径;这从 加载脚本url,然后插入并functionOrCode在成功时执行。

Code

代码

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

回答by Brock Adams

Use jQuery without fear of conflicts, by calling jQuery.noConflict(true). Like so:

使用 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);
}




But, For cross-browser scripts, why not take advantage of a nice, fast, local copy of jQuery, when you can?

但是,对于跨浏览器的脚本,为什么不尽可能利用一个不错的、快速的、本地的 jQuery 副本呢?

The following works as a Chrome userscript and a Greasemonkey script, and it uses the nice local @requirecopy of jQuery, if the platform supports it.

以下内容用作 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);
}

回答by Mottie

If the page already has jQuery, then just follow this template:

如果页面已经有 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);

回答by Stiger

The simple way is using requiredkeyword:

简单的方法是使用required关键字:

// @require     http://code.jquery.com/jquery-latest.js

回答by Jeff Atwood

There's a really easy way to get around including a full copy of jQuery for Chrome scripts when those scripts don't actually use any privileged features(GM_* functions, etc)...

当这些脚本实际上不使用任何特权功能(GM_* 函数等)时,有一种非常简单的方法可以绕过 Chrome 脚本的完整 jQuery 副本......

Simply insert the script itself into the page DOM and execute! The best part is that this technique works just as well on Firefox+Greasemonkey, so you can use the same script for both:

只需将脚本本身插入页面 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();
}

(unapologetically stolen from Shog9 on meta.stackoverflow since he didn't move it here, and I have to delete the meta post..)

(在 meta.stackoverflow 上从 Shog9 上毫无歉意地偷走了它,因为他没有把它移到这里,我不得不删除元帖子..)

回答by cyphunk

Easier solution: cut+paste the contents of jquery.min.js into the top of your user script. Done.

更简单的解决方案:将 jquery.min.js 的内容剪切并粘贴到用户脚本的顶部。完毕。

I found various problems with the recommended answers. The addJQuery() solution works on most pages but has bugs on many. If you run into issues just copy+paste the jquery contents into your script.

我发现推荐的答案存在各种问题。addJQuery() 解决方案适用于大多数页面,但在许多页面上存在错误。如果您遇到问题,只需将 jquery 内容复制并粘贴到您的脚本中即可。

回答by NVI

Also, you could pack your script with jQuery to Chrome extension. See Google Chrome's Content Scripts.

此外,您可以使用 jQuery 将脚本打包到 Chrome 扩展程序。请参阅Google Chrome 的内容脚本

Chrome extensions, unlike Greasemonkey scripts, can auto-update itself.

与 Greasemonkey 脚本不同,Chrome 扩展程序可以自动更新自身。

回答by gnarf

I wonder if you couldn't rely on document.defaultView.jQueryin your GM script ala:

我想知道你是否不能依赖document.defaultView.jQuery你的 GM 脚本 ala:

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($);
}

回答by Greg Bray

Another approach would be to modify your script to load jQuery manually. Example from http://joanpiedra.com/jquery/greasemonkey/:

另一种方法是修改您的脚本以手动加载 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
}

EDIT: DRATS!After testing it appears this code does not work since Google Chrome runs userscripts/extensions in a separate scope/process from the actual webpage. You can download the jQuery code using an XmlhttpRequest and then Eval it, but you have to host the code on a server that allows Cross-Origin Resource Sharingusing the Access-Control-Allow-Origin: *header. Sadly NONE of the current CDNswith jQuery support this.

编辑:DRATS!经过测试,此代码似乎不起作用,因为 Google Chrome 在与实际网页不同的范围/进程中运行用户脚本/扩展。您可以使用 XmlhttpRequest 下载 jQuery 代码,然后对其进行评估,但您必须将代码托管在允许使用标头进行跨源资源共享的服务器上Access-Control-Allow-Origin: *。遗憾的是,当前带有 jQ​​uery 的CDN 都不支持这一点。