【问题标题】:require jQuery to a safe variable in Tampermonkey script and console需要 jQuery 到 Tampermonkey 脚本和控制台中的安全变量
【发布时间】:2015-03-31 15:20:50
【问题描述】:

通常我使用以下代码sn-p,这个通常可以工作:

(function () {
    function main() {
        //...script body...
    }

    var OGloboCSS = { // var could be named anything, appropriate to the page
        addJQuery: function (callback) {
            var script = document.createElement("script");
            script.setAttribute("src", "https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/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);
        }
    };

    OGloboCSS.addJQuery(main);

})();

但偶尔我会在https://steamcommunity.com 上收到类似这样的错误:

拒绝加载脚本 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js' 因为它违反了以下内容安全政策指令: “script-src 'unsafe-eval' 'self' 'unsafe-inline' 'unsafe-eval' https://steamcommunity-a.akamaihd.net/https://api.steampowered.com/ http://www.google-analytics.comhttps://ssl.google-analytics.com https://www.google.comhttps://www.gstatic.com https://apis.google.com"。

解决方案基本上是,你必须改用 TamperMonkey 的 @require 标头指令,如下所示:

// @require      https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js
// ==/UserScript==

window.jQ = $;

(function () {
/*this used to be: function main() */
    //...same script body, without container function...

})();

这工作得很好,但它不能安全地将 jQuery 加载到jQ 变量,它破坏了$。真的有问题吗?是的,您可以从 steamcommunity.com 的讨论线程中的分页中断中看到这一点。

有什么方法可以@require jQ= 然后@grant jQ - 在 Tampermonkey 脚本和控制台中仍然给我jQ不会破坏页内变量

【问题讨论】:

  • 您可以使用 tampermonkey 调度外部脚本,并在该外部脚本中在顶部使用无冲突 JQ 或加载 amd。

标签: javascript jquery google-chrome tampermonkey


【解决方案1】:

除了避免版本冲突和破坏内容页面外,我在包含 jQuery 的默认用户脚本模板中做了一些其他事情。

下面的模板努力实现以下目标,以成为一个通用模板,将 jQuery 包含在新脚本中,无论内容页面的当前或未来状态如何,无论是否包含任何 jQuery版本。

  • 使用@grant none 避免安全沙箱
  • 通常不知道脚本的插入位置/执行时间
  • 为我们的用户脚本包含特定版本的 jQuery
  • 保留内容页面的 $ 和 jQuery 引用,无论它们是 jQuery 还是非 jQuery。
  • 允许我们的脚本为其 jQuery 版本使用 $ 别名

@grant none 的使用在这里很关键

//@grant          none

@grant none 适用于我 99% 的脚本。它允许通过维护 UserScript(this) 的全局范围来轻松访问内容页面的变量、函数和对象,并通过在两个范围中搜索变量、函数标识符来提供对内容页面的全局范围(窗口)的非限定访问 this , 窗口顺序。因此,如果您避免重复存在于内容页面中的标识符,则可以访问内容页面变量、函数和函数返回值而无需限定(“this.”或“window.”)。您可以在脚本中的任何位置执行此操作。

这突出了 OP 的原始问题。 @grant none 提供的便利也是 @require 指令在加载时覆盖窗口的 $ 和 jQuery 引用的原因。 jQuery 库已经包含 noConflict() 函数很长一段时间来处理这个问题。

我们可以立即对上述答案进行一些快速改进,以提高我们的安全性/兼容性/重用性。

window.jQ = $.noConflict(true);
  • 此调用没有明确地将 $ 限定为范围
  • 如果内容页面还包含其他一些别名为 $ 的库,则它不会工作得特别好。特别是如果内容页面在我们到达这里之前已经调用了 jQuery noConflict 本身。这是一个不必要的兔子洞。
  • 这段代码有些令人震惊地将对我们库的引用置于窗口范围内,以后内容页面很可能会以某种方式对其进行更改。 出于显而易见的原因,将任何内容暴露给窗口范围通常是不好的做法。

此代码改为

this.$ = window.jQuery.noConflict(true);
  • 将我们的库保留在它所属的范围内
  • 在我们的范围内为我们提供 $ 别名以继续在我们的脚本中使用
  • 将窗口的 $ 和 jQuery 别名恢复为我们的 jQuery 加载时的别名,无论它们实际上是否是 jQuery
  • 为我们提供了使用脚本加载的 jQuery 对象调用 noConflict 的最佳机会

最后一点可能有点矫枉过正,但为什么不明确并使用 jQuery 标识符进行 noConflict 调用。如果在这个调用运行时 $ 不是 jQuery,这将是我们的错(@require 用于另一个使用 $ 的库,在此代码运行之前自己使用它等),但可以免费防止以后的调试工作。

虽然我们可以在那里完成并感到高兴,但我们还可以更进一步,以确保在最广泛的页面之间的兼容性,以及通过最多种类的内容页面更改。

(function ($, undefined) {
  $(function () {
    //Your code here;
  });
})(window.jQuery.noConflict(true));

虽然仍不能保证,但此模式通过将 $ 别名保持在全局范围之外并利用 jQuery 的 DOM Ready 事件来确保页面完成,从而为您的功能代码提供了在最大范围的页面生命周期可能性中执行的最佳机会。顺便说一句,它还可以确保您的代码具有一致的未定义值。

// ==UserScript==
// @name          jQuery safe inclusion template
// @description   include jQuery and make sure window.$ is the content page's jQuery version, and this.$ is our jQuery version.
// @version       0.0.1
// @author        Sonic Beard
// @match         http://*.site.com/*
// @require       http://cdn.jsdelivr.net/jquery/2.1.3/jquery.min.js
// @grant         none
// ==/UserScript==

(function ($, undefined) {
  $(function () {
    //Your code here;
  });
})(window.jQuery.noConflict(true));

【讨论】:

  • 也让我看看如何奖励你..这是一个很好的答案,值得认可。
【解决方案2】:

TamperMonkey 似乎没有这样的功能,但另一种方法是立即调用 $.noConflict 并将 removeAll 参数设置为 true。这将导致 jQuery 将原始的 $jQuery 重置为原始值。

用户脚本示例:

// ==UserScript==
// @name         jQuery noConflict test
// @namespace    http://example.com/
// @version      0.1
// @description  test jQuery noConflict
// @author       You
// @match        https://steamcommunity.com/
// @require      https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js
// @grant        none
// ==/UserScript==

window.jQ = $.noConflict(true);

您可以从下面的示例控制台输入中看到,jQ 是由 @require 加载的 jQuery 2.1.3,jQuery 是页面加载的 jQuery 版本,$ 仍然是原始原型库对象,没有 jQuery 的 fn 属性就是证明。

控制台输入/输出示例:

> jQ.fn.jquery
< "2.1.3"
> jQuery.fn.jquery
< "1.11.1"
> $.fn
< undefined

【讨论】:

  • 感谢亚历山大。我今天很忙,但明天(2015 年 10 月 2 日)会考虑应用它——我很感激你的帮助,如果它对我有用,我会给你信用,即使你不能确定 Tampermonkey 的功能
  • 哈哈我几乎无法让它工作,因为我未能复制 UserScript 评论中的第一个字符 - 再次感谢,像广告宣传的那样工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-23
  • 1970-01-01
  • 2018-12-08
  • 1970-01-01
  • 2014-09-05
  • 1970-01-01
相关资源
最近更新 更多