Come posso usare jQuery negli script Greasemonkey in Google Chrome?


157

Come alcuni di voi sapranno, Google Chrome ha messo in seria limitazione gli script di Greasemonkey.

Chromium non supporta @require, @resource, unsafeWindow, GM_registerMenuCommand, GM_setValue, o GM_getValue.

Senza necessità, non riesco a trovare un modo per includere la libreria jQuery nello script Greasemonkey in Google Chrome.

Qualcuno ha qualche consiglio in merito?


19
Vale la pena notare che Google Chrome con Tampermonkey ha il supporto per @requireora, che è un approccio molto più semplice di quelli nelle risposte.
Steen Schütt,

2
Tampermonkey supporta anche unsafeWindow, che è molto utile per le pagine che hanno già jQuery. var $ = unsafeWindow.jQuery;
Tim Goodman,

1
@requirefunziona perfettamente su siti in cui non sei preoccupato di entrare in conflitto con una qualsiasi delle migliaia o milioni di altre librerie JS che si legano a $ al momento del caricamento. Tuttavia, se stai scrivendo uno script per un sito usando $ per qualcos'altro, o peggio ancora scrivendo uno script per essere eseguito su ogni sito di sempre, usa il meccanismo di caricamento relativamente sicuro spiegato da qui sotto.
GDorn,

Risposte:


192

Da "Suggerimento per gli script utente: utilizzo di jQuery - Blog di 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);

Invece delle 3 righe all'interno di addEventListener per 'load', non "callback ();" solo lavoro?
CRDX,

6
La mia pagina include già jQuery, ma sembra che il codice sopra sia ancora necessario per utilizzare jQuery nello script utente. Tuttavia, due include jQuery possono causare un conflitto, quindi la prima riga della funzione main () potrebbe essere jQuery.noConflict ();
slolife,

2
Ho modificato la linea script.textContent = "(" + callback.toString() + ")();";a script.textContent = "jQuery.noConflict();(" + callback.toString() + ")();";nel mio modello di script utente in modo non ci sarà alcun conflitto sorprendenti. :)
RCE,

1
@hippietrail In main(), è possibile utilizzare $.loadScript()e quindi eseguire tutto il resto al termine del caricamento di loadScript jQueryUI.
tghw

1
-1: Con quel metodo, il codice in mainverrà eseguito nel contesto della pagina di destinazione, il che significa che (tra le altre cose) si applica la politica di richiesta cross-site della pagina di destinazione - (ad esempio, ho dovuto rifiutare GM_xmlhttpRequestprima di vedere che lo faceva non aiutarmi). Alla fine copio semplicemente incollato il codice di jquery.min.js.
Jean Hominal

43

Ho scritto alcune funzioni basate sullo script di Erik Vold per aiutarmi a eseguire funzioni, codice e altri script in un documento. Puoi usarli per caricare jQuery nella pagina e quindi eseguire il codice nell'ambito globale window.

Esempio di utilizzo

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

Puoi fare clic qui per installarlo, se ritieni che non stia cercando di indurti a installare qualcosa di dannoso e che nessuno ha modificato il mio post per indicare qualcos'altro. Ricarica la pagina e dovresti vedere un bordo attorno al mio post.

funzioni

load(url, onLoad, onError)

Carica lo script urlnel documento. Facoltativamente, è possibile prevedere callback onLoade onError.

execute(functionOrCode)

Inserisce una funzione o una stringa di codice nel documento ed esegue. Le funzioni vengono convertite in codice sorgente prima di essere inserite, quindi perdono l'ambito / le chiusure correnti e vengono eseguite sotto l' windowambito globale .

loadAndExecute(url, functionOrCode)

Una scorciatoia; questo carica uno script da url, quindi inserisce ed esegue in functionOrCodecaso di successo.

Codice

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 Sì, è stato fondamentale per me salvare quei pochi personaggi. In realtà, mi sento piuttosto stupido per aver lasciato questo post usandolo così inutilmente. Lo rimuoverò.
Jeremy Banks,

18

Usa jQuery senza paura dei conflitti , chiamando jQuery.noConflict(true). Così:

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


Ma, per gli script cross-browser, perché non approfittare di una bella copia veloce e locale di jQuery, quando puoi?

Di seguito funziona come uno script utente Chrome e uno script Greasemonkey e utilizza la bella @requirecopia locale di jQuery, se la piattaforma lo supporta.

// ==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 Impressionante, tra tutte queste risposte la tua è l'unica che dice di usare @require, puoi anche usare $ = unsafeWindow.jQueryse la pagina ha jQuery (l'ho provato solo in Tampermonkey).
AMK,

Avvertenza: alcune versioni di IE non hanno console.log () a meno che tu non abbia installato gli strumenti di sviluppo, quindi lo script andrebbe in crash. Di solito lo scoprirai solo dopo aver rilasciato il tuo script oltre gli sviluppatori e le persone con QA.
Fase di analisi

1
@Parsingphase, IE è praticamente NA qui. L'ultima volta che ho controllato, IE non supporta ancora bene gli script utente (¿affatto?). È cambiato con IE 10?
Brock Adams,

Brock - buon punto, non riesco a tenere in mente la matrice di incompatibilità di IE. Quindi, non direttamente applicabile agli script utente (anche se sembra che le persone occasionalmente provino a implementare una soluzione IE), ma più di un gotcha generale.
Parsingphase,

15

Se la pagina ha già jQuery, segui questo modello:

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

Non penso che funzioni perché lo script utente non ha accesso alla finestra dei documenti?
Christoph,

@Christoph Funziona, ho e sto ancora usando uno script utente usando questo metodo.
Mottie,

1
Questo sta effettivamente iniettando lo script greasemonkey nella pagina. Quindi probabilmente ignora alcune delle garanzie che ha Greasemonkey.
Thymine,

1
@Thymine Ho notato che questo metodo inietta lo script utente in pagine indesiderate. Ho dovuto avvolgere la parte di iniezione in una ifdichiarazione che controlla il window.location.
Mottie,

12

Il modo semplice sta usando la requiredparola chiave:

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

È supportato solo dall'implementazione dell'estensione.
user2284570,

@ user2284570 È supportato da tutte le estensioni utente che ho trovato per qualsiasi browser.
Matt M.

@MattM. Voglio dire che non è necessario installare un'estensione su Opera e Chrome per eseguire script utente.
user2284570

7

Esiste un modo davvero semplice per spostarsi, inclusa una copia completa degli script jQuery per Chrome quando quegli script in realtà non utilizzano alcuna funzione privilegiata ( funzioni GM_ *, ecc.) ...

Basta inserire lo script stesso nella pagina DOM ed eseguire! La parte migliore è che questa tecnica funziona altrettanto bene su Firefox + Greasemonkey, quindi puoi usare lo stesso script per entrambi:

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

(rubato senza scuse da Shog9 su meta.stackoverflow dal momento che non lo ha spostato qui, e devo eliminare il meta post ..)


4

Inoltre, è possibile comprimere lo script con l'estensione jQuery a Chrome. Vedi gli script dei contenuti di Google Chrome .

Le estensioni di Chrome, a differenza degli script Greasemonkey, possono aggiornarsi automaticamente.


2
sì, sarebbe più facile. Ma per ora preferisco davvero mantenere il mio script tramite userscripts.org e non creare ridondanza con il repository delle estensioni di Google.
Alekc,

4
E costa $ 5 per caricare su Google Web Store.
Camilo Martin,

4

Soluzione più semplice: taglia + incolla il contenuto di jquery.min.js nella parte superiore dello script utente. Fatto.

Ho riscontrato vari problemi con le risposte consigliate. La soluzione addJQuery () funziona sulla maggior parte delle pagine ma ha molti bug. Se riscontri problemi, copia e incolla il contenuto jquery nel tuo script.


Sì, penso che questo abbia più senso, perché si può persino scrivere un piccolo script di build che genera una versione di Chrome facendo esattamente ciò che suggerisci qui.
Dkinzer,

2

Mi chiedo se non puoi fare affidamento sul document.defaultView.jQuerytuo script 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($);
}

1

Un altro approccio sarebbe quello di modificare lo script per caricare manualmente jQuery. Esempio da 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! Dopo il test sembra che questo codice non funzioni poiché Google Chrome esegue script / estensioni utente in un ambito / processo separato dalla pagina Web effettiva. È possibile scaricare il codice jQuery utilizzando un XmlhttpRequest e quindi valutarlo, ma è necessario ospitare il codice su un server che consente la condivisione delle risorse tra le origini utilizzando l' Access-Control-Allow-Origin: *intestazione. Purtroppo NESSUNO delle attuali CDN con jQuery supporta questo.


-1

Estensione perfetta per incorporare jQuery in Chrome Console nel modo più semplice che puoi immaginare. Questa estensione indica anche se jQuery è già stato incorporato nella pagina.

Questa estensione è stata utilizzata per incorporare jQuery in qualsiasi pagina desiderata. Permette di usare jQuery nella shell della console (puoi invocare la console Chrome con "Ctrl + Shift + j").

Per incorporare jQuery nella scheda selezionata, fare clic sul pulsante di estensione.

LINK all'estensione: https://chrome.google.com/extensions/detail/gbmifchmngifmadobkcpijhhldeeelkc


Questa non è davvero la risposta. E perché dovrei voler caricare jQuery se non ne avessi bisogno?
Vik,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.