Làm cách nào tôi có thể sử dụng jQuery trong tập lệnh Greasemonkey trong Google Chrome?


157

Như một số bạn có thể biết, Google Chrome đã đặt ra một số hạn chế nghiêm trọng đối với các tập lệnh Greasemonkey.

Chromium không hỗ trợ @require, @resource, unsafeWindow, GM_registerMenuCommand, GM_setValue, hoặc GM_getValue.

Không yêu cầu, tôi không thể tìm cách đưa thư viện jQuery vào tập lệnh Greasemonkey trong Google Chrome.

Có ai có một số lời khuyên trong vấn đề này?


19
Điều đáng chú ý là Google Chrome với Tampermonkey hiện đã hỗ trợ @require, đây là một cách tiếp cận đơn giản hơn nhiều so với các câu trả lời.
Steen Schütt

2
Tampermonkey cũng hỗ trợ unsafeWindow, rất tốt cho các trang đã có jQuery. var $ = unsafeWindow.jQuery;
Tim Goodman

1
@requirehoạt động tuyệt vời trên các trang web mà bạn không lo lắng về việc xung đột với bất kỳ hàng ngàn hoặc hàng triệu thư viện JS khác liên kết với $ khi tải. Tuy nhiên, nếu bạn đang viết một tập lệnh cho một trang web bằng cách sử dụng $ cho một thứ khác, hoặc thậm chí tệ hơn là viết một tập lệnh để chạy trên mọi trang web, hãy sử dụng cơ chế tải tương đối an toàn được giải thích bởi tghw bên dưới.
GDorn

Câu trả lời:


192

Từ "Mẹo tập lệnh người dùng: Sử dụng jQuery - Blog của 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);

Thay vì 3 dòng bên trong addEventListener cho 'load', sẽ không "gọi lại ();" chỉ làm việc?
crdx

6
Trang của tôi đã bao gồm jQuery, nhưng có vẻ như đoạn mã trên vẫn cần thiết để sử dụng jQuery trong mô tả người dùng. Tuy nhiên, hai jQuery bao gồm có thể gây ra xung đột, vì vậy dòng đầu tiên của hàm main () của bạn có thể cần phải là jQuery.noConflict ();
slolife

2
Tôi đã sửa đổi dòng script.textContent = "(" + callback.toString() + ")();";thành script.textContent = "jQuery.noConflict();(" + callback.toString() + ")();";trong mẫu tập lệnh người dùng của riêng tôi để không có bất kỳ xung đột đáng ngạc nhiên nào. :)
RCE

1
@hippietrail Trong main(), bạn có thể sử dụng $.loadScript()và sau đó chạy mọi thứ khác khi loadScript kết thúc tải jQueryUI.
tghw

1
-1: Với phương thức đó, mã trong mainsẽ thực thi trong ngữ cảnh của trang đích, nghĩa là (trong số những thứ khác) chính sách yêu cầu giữa các trang của trang đích được áp dụng - (ví dụ: tôi phải từ chối GM_xmlhttpRequesttrước khi thấy rằng nó đã làm không giúp tôi). Cuối cùng, tôi chỉ cần sao chép mã của jquery.min.js.
Jean Hominal

43

Tôi đã viết một vài chức năng dựa trên tập lệnh của Erik Vold để giúp tôi chạy các chức năng, mã và các tập lệnh khác trong tài liệu. Bạn có thể sử dụng chúng để tải jQuery vào trang và sau đó chạy mã theo windowphạm vi toàn cầu .

Cách sử dụng ví dụ

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

Bạn có thể bấm vào đây để cài đặt nó, nếu bạn tin rằng tôi không cố lừa bạn cài đặt thứ gì đó độc hại và không ai chỉnh sửa bài đăng của tôi để chỉ ra thứ khác. Tải lại trang và bạn sẽ thấy một đường viền xung quanh bài viết của tôi.

Chức năng

load(url, onLoad, onError)

Tải tập lệnh urlvào tài liệu. Tùy chọn, gọi lại có thể được cung cấp cho onLoadonError.

execute(functionOrCode)

Chèn một hàm hoặc chuỗi mã vào tài liệu và thực thi nó. Các chức năng được chuyển đổi thành mã nguồn trước khi được chèn, do đó chúng mất phạm vi / lần đóng hiện tại và được chạy bên dưới windowphạm vi toàn cầu .

loadAndExecute(url, functionOrCode)

Một lối tắt; điều này tải một tập lệnh từ url, sau đó chèn và thực thifunctionOrCode nếu thành công.

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 Vâng, điều quan trọng đối với tôi là cứu được vài nhân vật đó. Trên thực tế, tôi cảm thấy khá ngớ ngẩn vì đã để lại bài đăng này sử dụng nó quá vô nghĩa. Tôi sẽ xóa nó.
Jeremy Banks

18

Sử dụng jQuery mà không sợ xung đột , bằng cách gọi jQuery.noConflict(true). Thích như vậy:

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


Nhưng, đối với các tập lệnh trình duyệt chéo, tại sao bạn không tận dụng một bản sao đẹp, nhanh, cục bộ của jQuery, khi bạn có thể?

Phần sau hoạt động như một bản mô tả người dùng Chrome và tập lệnh Greasemonkey và nó sử dụng @requirebản sao jQuery đẹp, nếu nền tảng hỗ trợ nó.

// ==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 Ấn tượng, trong số tất cả những câu trả lời này, câu trả lời của bạn là câu trả lời duy nhất sử dụng @require, bạn cũng có thể sử dụng $ = unsafeWindow.jQuerynếu trang có jQuery (Tôi chỉ thử nghiệm điều này trong Tampermonkey).
AMK

Hãy cẩn thận: một số phiên bản IE không có console.log () trừ khi bạn đã cài đặt các công cụ dev, vì vậy tập lệnh sẽ bị sập. Thông thường, bạn sẽ khám phá điều này chỉ khi bạn phát hành tập lệnh của mình ngoài các nhà phát triển và dân gian QA.
Phân tích cú pháp

1
@Parsingphase, IE có khá nhiều NA ở đây. Tôi đã kiểm tra lần cuối, IE vẫn không hỗ trợ tốt các bản mô tả người dùng (cả?). Điều đó đã thay đổi với IE 10?
Brock Adams

Brock - điểm tốt, tôi thất bại trong việc giữ ma trận không tương thích của IE trong đầu. Vì vậy, không thể áp dụng trực tiếp cho các mô tả người dùng (mặc dù có vẻ như mọi người thỉnh thoảng cố gắng thực hiện một giải pháp IE), nhưng nhiều hơn một gotcha chung.
Phân tích cú pháp

15

Nếu trang đã có jQuery, thì chỉ cần làm theo mẫu này:

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

Tôi không nghĩ rằng điều này hoạt động vì người dùng không có quyền truy cập vào cửa sổ tài liệu?
Christoph

@Christoph Nó hoạt động, tôi có và tôi vẫn đang sử dụng một usercript bằng phương pháp này.
Mottie

1
Điều này thực sự là tiêm đoạn mã greasemonkey vào trang. Vì vậy, có lẽ bỏ qua một số biện pháp bảo vệ mà greasemonkey có.
Thymine

1
@Thymine Tôi đã nhận thấy rằng phương pháp này không đưa phần mô tả người dùng vào các trang không mong muốn. Tôi đã phải bọc phần tiêm trong một iftuyên bố kiểm tra window.location.
Mottie

12

Cách đơn giản là sử dụng requiredtừ khóa:

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

Nó chỉ được hỗ trợ bởi việc thực hiện mở rộng.
dùng2284570

@ user2284570 Nó được hỗ trợ bởi mọi tiện ích mở rộng usercript tôi có thể tìm thấy cho bất kỳ trình duyệt nào.
Matt M.

@MattM. Ý tôi là bạn không phải cài đặt tiện ích mở rộng trên Opera và Chrome để chạy mô tả người dùng.
dùng2284570

7

Có một cách thực sự dễ dàng để bao gồm một bản sao đầy đủ các tập lệnh jQuery cho Chrome khi các tập lệnh đó không thực sự sử dụng bất kỳ tính năng đặc quyền nào (các hàm GM_ *, v.v.) ...

Đơn giản chỉ cần chèn chính tập lệnh vào trang DOM và thực thi! Phần tốt nhất là kỹ thuật này hoạt động tốt trên Firefox + Greasemonkey, vì vậy bạn có thể sử dụng cùng một tập lệnh cho cả hai:

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

(bị đánh cắp một cách không chính thức từ Shog9 trên meta.stackoverflow vì anh ấy đã không di chuyển nó đến đây và tôi phải xóa bài đăng meta ..)


4

Ngoài ra, bạn có thể đóng gói tập lệnh của mình với tiện ích mở rộng jQuery sang Chrome. Xem Tập lệnh Nội dung của Google Chrome .

Các tiện ích mở rộng của Chrome, không giống như các tập lệnh Greasemonkey, có thể tự động cập nhật.


2
vâng, nó sẽ dễ dàng hơn. Nhưng tôi thực sự muốn duy trì tập lệnh của mình thông qua userscripts.org và không tạo ra sự dư thừa với kho lưu trữ tiện ích mở rộng của google.
Hà Lan

4
Và chi phí $ 5 để tải lên Google Web Store.
Camilo Martin

4

Giải pháp dễ dàng hơn: cắt + dán nội dung của jquery.min.js vào đầu tập lệnh người dùng của bạn. Làm xong.

Tôi tìm thấy nhiều vấn đề với các câu trả lời được đề nghị. Giải pháp addJQuery () hoạt động trên hầu hết các trang nhưng có nhiều lỗi. Nếu bạn gặp vấn đề, chỉ cần sao chép + dán nội dung jquery vào tập lệnh của bạn.


Vâng, tôi nghĩ rằng điều này có ý nghĩa nhất, bởi vì người ta thậm chí có thể tạo ra một kịch bản xây dựng nhỏ tạo ra một phiên bản chrome bằng cách thực hiện chính xác những gì bạn đề xuất ở đây.
dkinzer

2

Tôi tự hỏi nếu bạn không thể dựa vào document.defaultView.jQuerytập lệnh GM của mình:

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

Một cách tiếp cận khác là sửa đổi tập lệnh của bạn để tải jQuery theo cách thủ công. Ví dụ từ 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! Sau khi thử nghiệm, có vẻ như mã này không hoạt động do Google Chrome chạy các mô tả / tiện ích mở rộng trong một phạm vi / quy trình riêng biệt từ trang web thực tế. Bạn có thể tải xuống mã jQuery bằng XmlhttpRequest và sau đó là Eval, nhưng bạn phải lưu trữ mã trên máy chủ cho phép Chia sẻ tài nguyên nguồn gốc chéo bằng Access-Control-Allow-Origin: *tiêu đề. Đáng buồn là KHÔNG có CDN hiện tại với jQuery hỗ trợ điều này.


-1

Tiện ích mở rộng hoàn hảo để nhúng jQuery vào Chrome Console đơn giản như bạn có thể tưởng tượng. Phần mở rộng này cũng chỉ định nếu jQuery đã được nhúng vào trang.

Phần mở rộng này được sử dụng để nhúng jQuery vào bất kỳ trang nào bạn muốn. Nó cho phép sử dụng jQuery trong trình điều khiển vỏ (Bạn có thể gọi bảng điều khiển Chrome bằng "Ctrl + Shift + j").

Để nhúng jQuery vào tab đã chọn, nhấp vào nút mở rộng.

LIÊN KẾT đến tiện ích mở rộng: https://chrom.google.com.vn/extensions/detail/gbmifchmngifmadobkcpijhhldeeelkc


Đó thực sự không phải là câu trả lời. Và tại sao tôi muốn tải jQuery nếu tôi không cần?
Vik
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.