需要jQuery到Tampermonkey脚本和控制台中的安全变量

rob*_*más 10 javascript jquery google-chrome tampermonkey

通常我使用了以下代码片段,这通常有效:

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

})();
Run Code Online (Sandbox Code Playgroud)

但偶尔我会在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.com https:/ /ssl.google-analytics.com https://www.google.com https://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...

})();
Run Code Online (Sandbox Code Playgroud)

这工作得很好,但它不能安全地将jQuery加载到jQ变量,它是clobbers $.这真的是个问题吗?是的,您可以看到在steamcommunity.com的讨论主题中如何分页.

有没有办法@require jQ=然后@grant jQ- 仍然jQ在Tampermonkey脚本和控制台中给我两个,而不会破坏页内变量

小智 28

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

下面的模板努力实现以下目标,以便成为将jQuery包含在新脚本中的通用模板,而不管内容页面的任何版本的jQuery自身包含或缺乏内容页面的当前或未来状态.

  • 使用@grant none避免使用安全沙箱
  • 通常仍然不知道插入脚本的位置/执行时的位置
  • 为我们的UserScript包含特定版本的jQuery
  • 保留内容页面的$和jQuery引用它们可能是什么,jQuery与否.
  • 允许我们的脚本为其jQuery版本使用$ alias

使用@grant none是关键

//@grant          none
Run Code Online (Sandbox Code Playgroud)

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

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

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

window.jQ = $.noConflict(true);
Run Code Online (Sandbox Code Playgroud)
  • 此调用未明确限定$到范围
  • 如果内容页面还包含其他具有别名$的库,那么它将无法正常工作.特别是如果内容页面在我们到达之前已经调用了jQuery noConflict本身.这是一个不必要的兔子洞.
  • 这段代码有点令人担忧地将我们的库的引用放在窗口的范围内,以后内容页面可以很好地改变它.出于显而易见的原因,将任何东西暴露给窗口范围通常是不好的做法.

这个代码改为

this.$ = window.jQuery.noConflict(true);
Run Code Online (Sandbox Code Playgroud)
  • 将我们的图书馆保留在它所属的范围内
  • 给我们在我们的范围内的$别名继续在我们的脚本中使用
  • 将窗口的$和jQuery别名恢复到我们的jQuery加载时是否实际上是jQuery
  • 为我们提供了使用脚本加载的jQuery对象来调用noConflict的最佳机会

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

虽然我们可以在那里完成并且很开心,但我们还可以进一步确保在各种各样的页面之间的兼容性,以及通过各种各样的内容页面更改.

(function ($, undefined) {
  $(function () {
    //Your code here;
  });
})(window.jQuery.noConflict(true));
Run Code Online (Sandbox Code Playgroud)

虽然仍然无法保证,但这种模式通过将$别名保留在全局范围之外并利用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));
Run Code Online (Sandbox Code Playgroud)


Ale*_*ara 6

TamperMonkey似乎并不具有这样的功能,但替代将立即打电话$.noConflictremoveAll设定参数true.这将导致jQuery重置原始值$jQuery返回其原始值.

示例UserScript:

// ==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);
Run Code Online (Sandbox Code Playgroud)

你可以从下面的例子控制台输入看,jQ是一个由加载了jQuery 2.1.3 @require,jQuery是版本的jQuery的页面加载,并且$仍然是原来的原型库对象,通过不jQuery的证明fn财产.

控制台输入/输出示例:

> jQ.fn.jquery
< "2.1.3"
> jQuery.fn.jquery
< "1.11.1"
> $.fn
< undefined
Run Code Online (Sandbox Code Playgroud)