Wie kann ich jQuery in Greasemonkey-Skripten in Google Chrome verwenden?

157

Wie einige von Ihnen vielleicht wissen, hat Google Chrome die Greasemonkey-Skripte stark eingeschränkt.

Chrom nicht unterstützt @require, @resource, unsafeWindow, GM_registerMenuCommand, GM_setValue, oder GM_getValue.

Ohne Erfordernis kann ich keine Möglichkeit finden, die jQuery-Bibliothek in das Greasemonkey-Skript unter Google Chrome aufzunehmen.

Hat jemand einen Rat in dieser Angelegenheit?

Alekc
quelle
19
Es ist erwähnenswert, dass Google Chrome mit Tampermonkey derzeit Unterstützung bietet. Dies @requireist ein weitaus einfacherer Ansatz als in den Antworten.
Steen Schütt
2
Tampermonkey unterstützt auch unsafeWindow, was sehr gut für Seiten ist, die bereits jQuery haben. var $ = unsafeWindow.jQuery;
Tim Goodman
1
@requireFunktioniert hervorragend auf Websites, auf denen Sie sich keine Sorgen über Konflikte mit Tausenden oder Millionen anderer JS-Bibliotheken machen müssen, die beim Laden an $ gebunden werden. Wenn Sie jedoch ein Skript für eine Site mit $ für etwas anderes schreiben oder noch schlimmer, ein Skript für jede Site schreiben, verwenden Sie den vergleichsweise sicheren Lademechanismus, der unter tghw unten erläutert wird .
GDorn

Antworten:

192

Aus "User Script Tipp: Verwenden von jQuery - Erik Volds Blog"

// ==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);
tghw
quelle
Anstelle der 3 Zeilen in addEventListener für 'load' würde nicht "callback ();" einfach arbeiten?
Crdx
6
Meine Seite enthält bereits jQuery, aber es scheint, dass der obige Code noch benötigt wird, um jQuery im Userscript zu verwenden. Zwei jQuery-Includes können jedoch einen Konflikt verursachen. Daher muss die erste Zeile Ihrer main () -Funktion möglicherweise jQuery.noConflict () sein.
Slolife
2
Ich habe die Linie geändert , script.textContent = "(" + callback.toString() + ")();";um script.textContent = "jQuery.noConflict();(" + callback.toString() + ")();";in meiner eigenen Benutzerskriptvorlage so wird es keine überraschenden Konflikte sein. :)
RCE
1
@hippietrail In main()können Sie $.loadScript()alles andere verwenden und dann ausführen, wenn loadScript mit dem Laden von jQueryUI fertig ist.
Tghw
1
-1: Bei dieser Methode wird der Code in mainim Kontext der Zielseite ausgeführt, was bedeutet, dass (unter anderem) die standortübergreifende Anforderungsrichtlinie der Zielseite gilt - (z. B. musste ich erneut einwerfen, GM_xmlhttpRequestbevor ich dies sah hilf mir nicht). Am Ende kopiere ich einfach den Code von jquery.min.js.
Jean Hominal
43

Ich habe einige Funktionen basierend auf dem Erik Vold-Skript geschrieben , damit ich Funktionen, Code und andere Skripte in einem Dokument ausführen kann. Sie können sie verwenden, um jQuery in die Seite zu laden und dann Code im globalen windowBereich auszuführen .

Beispiel Verwendung

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

Sie können hier klicken , um es zu installieren, wenn Sie darauf vertrauen, dass ich Sie nicht dazu verleiten möchte, etwas Bösartiges zu installieren, und dass niemand meinen Beitrag so bearbeitet hat, dass er auf etwas anderes verweist. Laden Sie die Seite neu und Sie sollten einen Rand um meinen Beitrag sehen.

Funktionen

load(url, onLoad, onError)

Lädt das Skript unter urlin das Dokument. Optional können Rückrufe für onLoadund vorgesehen werden onError.

execute(functionOrCode)

Fügt eine Funktion oder Codezeichenfolge in das Dokument ein und führt es aus. Die Funktionen werden vor dem Einfügen in Quellcode konvertiert, sodass sie ihren aktuellen Bereich / ihre aktuellen Abschlüsse verlieren und unter dem globalen windowBereich ausgeführt werden.

loadAndExecute(url, functionOrCode)

Eine Abkuerzung; Dadurch wird ein Skript von urlgeladen und functionOrCodebei Erfolg eingefügt und ausgeführt .

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); });
}
Jeremy Banks
quelle
@cyphunk Ja, es war entscheidend für mich, diese wenigen Zeichen zu speichern. Eigentlich fühle ich mich ziemlich dumm, diesen Beitrag so sinnlos verlassen zu haben. Ich werde es entfernen.
Jeremy Banks
18

Verwenden Sie jQuery ohne Angst vor Konflikten , indem Sie anrufen jQuery.noConflict(true). Wie so:

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


Aber für Cross-Browser - Scripts, warum nicht nutzen von einem schönen, schnell, lokale Kopie von jQuery, wenn Sie können?

Das folgende Skript funktioniert als Chrome-Benutzer- und Greasemonkey-Skript und verwendet die schöne lokale @requireKopie von jQuery, sofern die Plattform dies unterstützt.

// ==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);
}
Brock Adams
quelle
3
+1 Beeindruckend, von all diesen Antworten ist Ihre die einzige, die sagt, dass @require verwendet werden soll. Sie können sie auch verwenden, $ = unsafeWindow.jQuerywenn die Seite jQuery enthält (ich habe dies nur in Tampermonkey getestet).
AMK
Vorsichtsmaßnahme: Einige Versionen von IE verfügen nicht über console.log (), es sei denn, Sie haben Entwicklungstools installiert, sodass das Skript abstürzen würde. Normalerweise werden Sie dies erst entdecken, wenn Sie Ihr Skript über Entwickler und QA-Leute hinaus veröffentlicht haben.
Parsingphase
1
@Parsingphase, IE ist hier so ziemlich NA. Zuletzt habe ich überprüft, dass der IE Benutzer-Skripte immer noch nicht gut unterstützt (¿überhaupt?). Hat sich das mit IE 10 geändert?
Brock Adams
Brock - guter Punkt, ich kann die Inkompatibilitätsmatrix des IE nicht im Kopf behalten. Also nicht direkt auf Userscripts anwendbar (obwohl es den Anschein hat, dass gelegentlich versucht wird, eine IE-Lösung zu implementieren), sondern eher ein allgemeines Problem.
Parsingphase
15

Wenn die Seite bereits jQuery enthält, folgen Sie einfach dieser Vorlage:

// ==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);
Mottie
quelle
Ich glaube nicht, dass dies funktioniert, weil das Userscript keinen Zugriff auf das Dokumentfenster hat.
Christoph
@Christoph Es funktioniert, ich habe und ich benutze immer noch ein Userscript mit dieser Methode.
Mottie
1
Dadurch wird das Greasemonkey-Skript tatsächlich in die Seite eingefügt. Umgeht wahrscheinlich einige der Sicherheitsvorkehrungen, die greasemonkey hat.
Thymin
1
@Thymine Ich habe festgestellt, dass diese Methode das Userscript in unerwünschte Seiten einfügt. Ich musste den Injektionsabschnitt in eine ifAnweisung einwickeln, die das überprüft window.location.
Mottie
12

Der einfache Weg ist die Verwendung des requiredSchlüsselworts:

// @require     http://code.jquery.com/jquery-latest.js
Stiger
quelle
Es wird nur von der Erweiterungsimplementierung unterstützt.
user2284570
@ user2284570 Es wird von jeder Userscript-Erweiterung unterstützt, die ich für jeden Browser finden konnte.
Matt M.
@ MattM. Ich meine, Sie müssen keine Erweiterung in Opera und Chrome installieren, um Benutzerskripte auszuführen.
user2284570
7

Es gibt eine wirklich einfache Möglichkeit, sich fortzubewegen, einschließlich einer vollständigen Kopie von jQuery für Chrome-Skripten, wenn diese Skripte keine privilegierten Funktionen (GM_ * -Funktionen usw.) verwenden ...

Fügen Sie einfach das Skript selbst in das Seiten-DOM ein und führen Sie es aus! Das Beste daran ist, dass diese Technik unter Firefox + Greasemonkey genauso gut funktioniert, sodass Sie für beide dasselbe Skript verwenden können:

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

(Unentschuldigt von Shog9 auf meta.stackoverflow gestohlen, da er es nicht hierher verschoben hat und ich den Meta-Beitrag löschen muss ..)

Jeff Atwood
quelle
4

Sie können Ihr Skript auch mit der Erweiterung jQuery to Chrome packen. Siehe Inhaltsskripte von Google Chrome .

Chrome-Erweiterungen können sich im Gegensatz zu Greasemonkey-Skripten automatisch aktualisieren.

NVI
quelle
2
Ja, es wäre einfacher. Aber ich ziehe es wirklich vor, mein Skript vorerst über userscripts.org zu verwalten und keine Redundanz mit dem Google Extensions Repository zu erstellen.
Alekc
4
Das Hochladen in den Google Web Store kostet 5 US-Dollar.
Camilo Martin
4

Einfachere Lösung: Schneiden Sie den Inhalt von jquery.min.js aus und fügen Sie ihn oben in Ihr Benutzerskript ein. Getan.

Ich habe verschiedene Probleme mit den empfohlenen Antworten gefunden. Die Lösung addJQuery () funktioniert auf den meisten Seiten, weist jedoch auf vielen Seiten Fehler auf. Wenn Sie auf Probleme stoßen, kopieren Sie einfach den Inhalt der Abfrage und fügen Sie ihn in Ihr Skript ein.

Cyphunk
quelle
Ja, ich denke, das ist am sinnvollsten, weil man sogar ein kleines Build-Skript schreiben kann, das eine Chrome-Version generiert, indem man genau das tut, was man hier vorschlägt.
Dkinzer
2

Ich frage mich, ob Sie sich document.defaultView.jQueryin Ihrem GM-Skript nicht auf Folgendes verlassen können:

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

Ein anderer Ansatz wäre, Ihr Skript so zu ändern, dass jQuery manuell geladen wird. Beispiel von 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! Nach dem Testen scheint dieser Code nicht zu funktionieren, da Google Chrome Benutzerskripte / -erweiterungen in einem von der eigentlichen Webseite getrennten Bereich / Prozess ausführt. Sie können den jQuery-Code mithilfe einer XmlhttpRequest herunterladen und dann auswerten. Sie müssen den Code jedoch auf einem Server hosten, der die gemeinsame Nutzung von Ressourcen mithilfe des Access-Control-Allow-Origin: *Headers ermöglicht. Leider unterstützt KEINER der aktuellen CDNs mit jQuery dies.

Greg Bray
quelle
-1

Perfekte Erweiterung, um jQuery so einfach wie möglich in die Chrome Console einzubetten. Diese Erweiterung zeigt auch an, ob jQuery bereits in die Seite eingebettet wurde.

Mit dieser Erweiterung wird jQuery in eine beliebige Seite eingebettet. Es ermöglicht die Verwendung von jQuery in der Konsolen-Shell (Sie können die Chrome-Konsole mit "Strg + Umschalt + j" aufrufen).

Um jQuery in die ausgewählte Registerkarte einzubetten, klicken Sie auf die Erweiterungsschaltfläche.

LINK zur Erweiterung: https://chrome.google.com/extensions/detail/gbmifchmngifmadobkcpijhhldeeelkc

Andrey
quelle
Das ist wirklich nicht die Antwort. Und warum sollte ich jQuery laden wollen, wenn ich es nicht musste?
Vik