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


157

如您所知,谷歌浏览器对Greasemonkey脚本进行了一些严格的限制。

铬不支持@require@resourceunsafeWindowGM_registerMenuCommandGM_setValue,或GM_getValue

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

有人在这件事上有什么建议吗?


19
值得注意的是,带有Tampermonkey的Google Chrome @require现在已经支持,这比答案中的方法简单得多。
SteenSchütt2013年

2
Tampermonkey还支持unsafeWindow,这对于已经具有jQuery的页面非常有用。var $ = unsafeWindow.jQuery;
Tim Goodman 2013年

1
@require在您不担心与加载时绑定到$的成千上万个其他JS库中的任何一个冲突的站点上,它们都可以很好地工作。但是,如果您要使用$编写其他站点的脚本,或者更糟糕的是编写要在每个站点上运行的脚本,请使用下面tghw解释的相对安全的加载机制。
GDorn

Answers:


192

来自“用户脚本技巧:使用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);

而不是addEventListener内的3行用于“加载”,而不是“ callback();” 上班吗
crdx

6
我的页面已经包含jQuery,但似乎仍需要上面的代码才能在用户脚本中使用jQuery。但是,包含两个jQuery可能会导致冲突,因此main()函数的第一行可能需要为jQuery.noConflict();。
slolife 2011年

2
我已经在自己的用户脚本模板中将行修改script.textContent = "(" + callback.toString() + ")();";script.textContent = "jQuery.noConflict();(" + callback.toString() + ")();";,因此不会出现任何令人惊讶的冲突。:)
RCE 2012年

1
@hippietrail在中main(),您可以使用$.loadScript(),然后在loadScript完成加载jQueryUI时运行其他所有内容。
tghw 2012年

1
-1:使用该方法,in中的代码main将在目标页面的上下文中执行,这意味着(除其他事项外)目标页面的跨站点请求策略适用-(例如,GM_xmlhttpRequest在看到它确实需要重新插入之前,不帮我)。最后,我只是复制粘贴了的代码jquery.min.js
Jean Hominal 2013年

43

我已经基于Erik Vold的脚本编写了一些函数,以帮助我在文档中运行函数,代码和其他脚本。您可以使用它们将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); });
}

@cyphunk是的,对我来说至关重要的是保存那几个字符。其实,我这么愚蠢地离开了这篇文章,我感到非常愚蠢。我将其删除。
杰里米·班克斯

18

通过调用来使用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);
}

3
+1令人印象深刻,在所有这些答案中,您的答案是唯一使用@require的答案,您也可以使用$ = unsafeWindow.jQuery该页面是否具有jQuery(我只在Tampermonkey中对此进行了测试)。
AMK 2012年

注意:某些版本的IE除非安装了开发工具,否则没有console.log(),因此脚本将崩溃。通常,只有在发布脚本后,开发人员和质量检查人员才能发现这一点。
解析阶段

1
@ Parsingphase,IE在这里几乎不适用。最后我检查了一下,IE仍然不很好地支持用户脚本(根本不支持)。IE 10改变了吗?
布罗克·亚当斯

布罗克(Brock)-好点,我无法将IE的不兼容性矩阵牢记在心。因此,这并不直接适用于用户脚本(尽管确实有人偶尔尝试实现IE解决方案),但更多的是一般的陷阱。
解析阶段

15

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

我认为这行不通,因为用户脚本无法访问文档窗口?
克里斯多夫

@Christoph它确实起作用,我已经使用该方法,但仍在使用用户脚本
Mottie 2012年

1
实际上,这是在页面中注入油膏猴子脚本。因此,可能绕过了Greasemonkey具有的一些保护措施。
Thymine

1
@胸腺嘧啶我已经注意到,此方法确实将用户脚本注入到不需要的页面中。我不得不将注入部分包装在if检查的语句中window.location
Mottie

12

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

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

它仅受扩展实现支持。
user2284570 2014年

@ user2284570我可以在任何浏览器中找到的每个用户脚本扩展都支持该功能。
马特M.18年

@MattM。我的意思是您不必在Opera和Chrome上安装扩展程序即可运行用户脚本。
user2284570'4

7

当这些脚本实际上未使用任何特权功能(GM_ *功能等)时,有一种非常简单的方法可以解决,包括完整的jQuery for Chrome脚本副本。

只需将脚本本身插入页面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上从Shog9偷窃了,因为他没有将其移到这里,所以我必须删除该meta帖子。)


4

另外,您可以将脚本与jQuery一起打包到Chrome扩展程序中。请参阅Google Chrome浏览器的内容脚本

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


2
是的,这样会更容易。但是我真的很喜欢暂时通过userscripts.org维护我的脚本,而不是使用Google扩展存储库创建冗余。
Alekc

4
上载到Google Web Store的费用为5美元。
卡米洛·马丁

4

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

我发现了建议答案的各种问题。addJQuery()解决方案可在大多数页面上使用,但在许多页面上都有错误。如果遇到问题,只需将jquery内容复制并粘贴到脚本中。


是的,我认为这是最合理的,因为您甚至可以编写一些构建脚本,通过完全按照您在此处的建议来生成chrome版本。
dkinzer

2

我想知道您是否不能依赖于document.defaultView.jQueryGM脚本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($);
}

1

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

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


-1

完美的扩展,将jQuery嵌入到Chrome控制台中就可以想象得到的简单。此扩展名还指示jQuery是否已嵌入到页面中。

该扩展用于将jQuery嵌入到所需的任何页面中。它允许在控制台外壳中使用jQuery(您可以通过“ Ctrl + Shift + j”调用Chrome控制台)。

要将jQuery嵌入所选选项卡,请单击扩展按钮。

链接到扩展程序:https : //chrome.google.com/extensions/detail/gbmifchmngifmadobkcpijhhldeeelkc


那真的不是答案。如果不需要的话,为什么还要加载jQuery?
维克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.