【问题标题】:Replace jQuery version of a page with Greasemonkey用 Greasemonkey 替换页面的 jQuery 版本
【发布时间】:2011-10-09 00:51:02
【问题描述】:

如何用greasemonkey 替换页面的jquery 版本?

我正在尝试使用较新版本的 jquery 测试网站,但我没有开发环境。

【问题讨论】:

    标签: jquery greasemonkey


    【解决方案1】:

    不确定 Greasemonkey,但修改任何资源(网址、图像、脚本)的简单方法是使用 Requestly 重定向规则。

    1. 从图标打开 Requesly 应用(或导航到 http://app.requestly.in/rules
    2. 点击“新规则”
    3. 选择“重定向请求”
    4. 输入请求源(在您的情况下,"URL""Equals":[url-to-jquery eg: "http://some-host.com/jquery1.4.js"]
    5. 输入目标(在您的情况下,为所需 jquery 版本 CDN 的 URL,例如:“http://any-host.com/jquery3.2.js”)
    6. 点击保存
    7. 完成!现在,您的浏览器对源 url 的所有请求都将被重定向到您定义的目标 url。

    注意:

    • 如果您没有 CDN,您可以使用 Requestly 库在 Web 上托管文件。然后选择目标网址字段下方的“从库中选择”。
    • 使用取消请求规则阻止现有请求可以达到相同的结果。然后使用插入脚本规则将您的脚本版本插入网页。

    PS:我在 Requestly 工作。

    【讨论】:

      【解决方案2】:

      创建开发环境、使用源代码控制和书面发布清单将为您省去很多麻烦(并且是大多数有偿工作的要求)。
      ~~~

      在现有页面(您无法控制)上替换 jQuery 版本的最佳方法是:

      1. 停止加载页面的原生 jQuery。
      2. 创建一个 <script> 节点,其中包含您想要的 jQuery 版本,该节点在之前加载任何使用 jQuery 的后续脚本。

      不幸的是,Greasemonkey 不能做到#1。它只能在页面加载后 篡改页面的原生 jQuery -- 这种方法可能有效,但会减慢页面速度并冒竞争条件的风险。

      所以,我推荐两个工具的解决方案:

      1. 确保您的 Firefox 具有the Adblock add-on(这是一个可以随意使用的优秀插件)和/或the RequestPolicy add-on

      2. 使用 AdblockRequestPolicy 暂时阻止旧的 jQuery。
        例如,对于 StackOverflow,阻止 http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js。 (请注意,RequestPolicy 允许您将 URL 阻止限制为仅特定站点。)

      3. 然后使用 Greasemonkey 在页面开头加载所需版本的 jQuery(无论 AdblockRequestPolicy 设置如何,它都可以执行此操作)。

        例如,这个脚本会将 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 就是这种情况。)

      【讨论】:

      • 原来我也在尝试做同样的事情!我正在尝试在 FF56 中重新加载 SO,因为谷歌 CDN 是 0 速度的阈值。我使用 uMatrix 来阻止它。准备好文档后,将脚本节点扫描到队列中,从 jquery 开始反转并将每个脚本附加到头部。在此之前,我尝试了 run@document-start 和 event beforescriptexecute 来拦截,页面加载阻塞。现在我用 window.eval() 尝试你的方式。它完美无缺。所以。只是为了感谢你的 0timout 技巧。
      【解决方案3】:

      我知道您在询问有关 jQuery 和 Greasemonkey 的问题,但请让我提出一个完全不同的替代方案,Fiddler

      如果您正在使用新版本的 jQuery 测试网站,并且您实际上想要测试任何重大更改等...您想要测试该网站 ,而基于 JavaScript(greasemonkey)的事后替换不是准确的模拟。

      使用 fiddler,您可以替换浏览器请求的 jQuery 文件(浏览器不知道)。这样你实际上是在完全测试它,你直接在页面中删除新版本,没有页面内的 JS 技巧可能根本不准确(处理程序已经连接,加载顺序等) )

      Eric Law(Fiddler 的创建者)有一篇很棒的博文,介绍了如何完全做到这一点:

      Swapping out JQuery with Fiddler

      这篇文章是为了用完整版(也很方便!)替换缩小版(也很方便!)用于调试的较新版本,请务必注意两种用途......它们都是非常有助于节省一些调试/测试时间。

      【讨论】:

        【解决方案4】:

        什么对我的情况不起作用,似乎适合这个问题,不需要阻止程序。在 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 文件加载失败,此方法将不起作用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-06-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-04-24
          • 2014-12-31
          • 1970-01-01
          相关资源
          最近更新 更多