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

正如你们中的一些人可能知道的那样,Google Chrome 对 Greasemonkey 脚本进行了一些严格的限制。

铬不支持 @require@resourceunsafeWindowGM_registerMenuCommandGM_setValueGM_getValue

如果没有要求,我无法找到一种方法将 jQuery 库包含在谷歌浏览器的 Greasemonkey 脚本中。

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

65765 次浏览

另外,你也可以用 jQuery 来打包你的脚本到 Chrome 扩展,参见 谷歌浏览器的内容脚本

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

另一种方法是修改脚本以手动加载 jQuery:

// 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 代码,然后对其进行 Eval,但是您必须将代码驻留在允许使用 Access-Control-Allow-Origin: *头的 跨来源资源共享的服务器上。遗憾的是,使用 jQuery 的 没有当前的 CDN支持这一点。

将 jQuery 嵌入 Chrome 控制台的完美扩展,就像你想象的那样简单。这个扩展还表明 jQuery 是否已经嵌入到页面中。

这个扩展用于将 jQuery 嵌入到任何您想要的页面中。它允许在控制台 shell 中使用 jQuery (您可以通过“ Ctrl + Shift + j”调用 Chrome 控制台)。

要将 jQuery 嵌入到选定的选项卡中,请单击扩展按钮。

链接到分机: https://chrome.google.com/extensions/detail/gbmifchmngifmadobkcpijhhldeeelkc

我想知道你是否不能依赖 document.defaultView.jQuery在你的通用汽车脚本中,阿拉伯语:

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

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

有一个非常简单的方法来解决这个问题,包括一个完整的 jQuery for Chrome 脚本 这些脚本实际上并没有使用任何特权功能(GM _ * 函数等) ..。

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

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

我已经编写了一些基于 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处的脚本加载到文档中。可以选择为 onLoadonError提供回调。

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

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

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

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

通过调用 jQuery.noConflict(true)使用 jQuery 不用担心冲突,如下所示:

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 脚本,如果平台支持的话,它使用了 jQuery 的漂亮的本地 @require副本。

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

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

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