【发布时间】:2011-10-09 00:51:02
【问题描述】:
如何用greasemonkey 替换页面的jquery 版本?
我正在尝试使用较新版本的 jquery 测试网站,但我没有开发环境。
【问题讨论】:
标签: jquery greasemonkey
如何用greasemonkey 替换页面的jquery 版本?
我正在尝试使用较新版本的 jquery 测试网站,但我没有开发环境。
【问题讨论】:
标签: jquery greasemonkey
不确定 Greasemonkey,但修改任何资源(网址、图像、脚本)的简单方法是使用 Requestly 重定向规则。
注意:
PS:我在 Requestly 工作。
【讨论】:
创建开发环境、使用源代码控制和书面发布清单将为您省去很多麻烦(并且是大多数有偿工作的要求)。
~~~
在现有页面(您无法控制)上替换 jQuery 版本的最佳方法是:
<script> 节点,其中包含您想要的 jQuery 版本,该节点在之前加载任何使用 jQuery 的后续脚本。不幸的是,Greasemonkey 不能做到#1。它只能在页面加载后 篡改页面的原生 jQuery -- 这种方法可能有效,但会减慢页面速度并冒竞争条件的风险。
所以,我推荐两个工具的解决方案:
确保您的 Firefox 具有the Adblock add-on(这是一个可以随意使用的优秀插件)和/或the RequestPolicy add-on。
使用 Adblock 或 RequestPolicy 暂时阻止旧的 jQuery。
例如,对于 StackOverflow,阻止 http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js。 (请注意,RequestPolicy 允许您将 URL 阻止限制为仅特定站点。)
然后使用 Greasemonkey 在页面开头加载所需版本的 jQuery(无论 Adblock 或 RequestPolicy 设置如何,它都可以执行此操作)。
例如,这个脚本会将 Meta SO 的 jQuery 升级到 1.6.2,并结合步骤 2 中的块:
// ==UserScript==
// @name _upgrade jQuery
// @include http://meta.stackexchange.com/questions/*
// @run-at document-start
// ==/UserScript==
/*--- Important!
(1) We need another add-on, besides Greasemonkey, to
disable the old, undesired script.
(2) The DOM is not available yet
(@run-at == document-start).
(3) We cannot use a loop to check for the DOM because
loading is halted while the loop runs.
(4) setTimeout() and setInterval() are not fast enough due
to minimum interval clamping. By the time they detect
the DOM, scripts that we need to precede may have
loaded.
(5) Therefor, we use a "set Zero Timeout" function as
explained by David Baron at
http://dbaron.org/log/20100309-faster-timeouts .
(6) By the time FF reports that the `document.head` is
available, several head elements have loaded!
(Is this a bug?)
That means that if any dependent scripts are loaded
before we can inject our jQuery version, then we must
also reload those dependent scripts.
*/
////// setZeroTimeout() implementation: BEGIN
/*--- Only add setZeroTimeout to the window object, and hide
everything else in a closure.
*/
( function () {
var timeouts = [];
var messageName = "zero-timeout-message";
/*--- Like setTimeout, but only takes a function argument.
There's no time argument (always zero) and no arguments.
You have to use a closure.
*/
function setZeroTimeout(fn) {
timeouts.push(fn);
window.postMessage(messageName, "*");
}
function handleMessage(event) {
if (event.source == window && event.data == messageName) {
event.stopPropagation();
if (timeouts.length > 0) {
var fn = timeouts.shift();
fn();
}
}
}
window.addEventListener ("message", handleMessage, true);
// Add the one thing we want added to the window object.
window.setZeroTimeout = setZeroTimeout;
})();
////// setZeroTimeout() implementation: END
/*--- Now wait for the DOM and then add our version of jQuery,
first thing.
*/
function SearchForDOM () {
var targetNode;
if (typeof document.head == "undefined")
targetNode = document.querySelector ("head, body");
else
targetNode = document.head;
if (targetNode) {
var scriptNode = document.createElement ("script");
scriptNode.src = 'http://ajax.googleapis.com/ajax/'
+ 'libs/jquery/1.6.2/jquery.min.js';
targetNode.appendChild (scriptNode);
/*--- By the time FF reports that the head element is
available, a key dependent script has loaded!
So, we reload it here, so that it can run with jQuery
available.
*/
var scriptNode = document.createElement ("script");
scriptNode.src = location.protocol
+ '\/\/' + location.host
+ '/content/js/stub.js?v=49f661361016';
targetNode.appendChild (scriptNode);
}
else
setZeroTimeout (SearchForDOM);
}
SearchForDOM ();
注意:由于 JS、GM 和 Firefox 的限制,可能还需要重新加载依赖于 jQuery 的脚本。 (目前 Meta Stack Overflow 就是这种情况。)
【讨论】:
我知道您在询问有关 jQuery 和 Greasemonkey 的问题,但请让我提出一个完全不同的替代方案,Fiddler。
如果您正在使用新版本的 jQuery 测试网站,并且您实际上想要测试任何重大更改等...您想要测试该网站 是,而基于 JavaScript(greasemonkey)的事后替换不是准确的模拟。
使用 fiddler,您可以替换浏览器请求的 jQuery 文件(浏览器不知道)。这样你实际上是在完全测试它,你直接在页面中删除新版本,没有页面内的 JS 技巧可能根本不准确(处理程序已经连接,加载顺序等) )
Eric Law(Fiddler 的创建者)有一篇很棒的博文,介绍了如何完全做到这一点:
这篇文章是为了用完整版(也很方便!)替换缩小版(也很方便!)或用于调试的较新版本,请务必注意两种用途......它们都是非常有助于节省一些调试/测试时间。
【讨论】:
什么对我的情况不起作用,似乎适合这个问题,不需要阻止程序。在 GreaseMonkey:
// ==UserScript==
// @name alternative jquery
// @namespace ben@host
// @description intercept
// @include https://somehost.com/*
// @grant GM_getResourceText
// @resource jquery_new jquery_new.js
// @run-at document-start
// @version 1
// ==/UserScript==
var jquery_source = GM_getResourceText( 'jquery_new' );
console.log('jQuery Lenght =',jquery_source.length);
window.addEventListener('beforescriptexecute',
function(e){
if (e.target.src &&
e.target.src.search('/1.12.4/jquery.min.js') >= 0 ) {
console.log('intercepted: '+e.target.src);
e.preventDefault();
e.stopPropagation();
window.eval(jquery_source);
}
});
注意:缺点 - beforescriptexecute 在原始脚本被检索并准备好执行后触发,因此如果原始外部 js 文件加载失败,此方法将不起作用。
【讨论】: