通常我使用以下代码片段,这通常有效:
(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 上遇到这样的错误:
Refused to load the script 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js' because it violates the following Content Security Policy directive: "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
header 指令,如下所示:
// @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脚本和控制台,没有破坏页内变量?
最佳答案
除了避免版本冲突和破坏内容页面之外,我在包含 jQuery 的默认用户脚本模板中做了一些其他事情。
下面的模板努力实现以下目标,以成为在新脚本中包含 jQuery 的通用模板,无论内容页面当前或 future 的状态是否包含或不包含任何 jQuery版本。
- 使用@grant none 避免安全沙箱
- 通常对脚本的插入位置/执行时间一无所知
- 为我们的 UserScript 添加特定版本的 jQuery
- 保留内容页面的 $ 和 jQuery 引用,不管它们是什么,jQuery 与否。
- 允许我们的脚本为其 jQuery 版本使用 $ 别名
@grant none 的使用是这里的关键
//@grant none
@grant none 适用于我 99% 的脚本。它通过维护 UserScript(this) 的全局作用域,并通过在两个作用域中搜索变量、函数标识符来提供对内容页面全局作用域(window) 的非限定访问,从而轻松访问内容页面的变量、函数和对象, 窗序。因此,如果您避免重复存在于内容页面中的标识符,您可以访问内容页面变量、函数和函数返回值而无需限定(“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));
关于javascript - 需要 jQuery 到 Tampermonkey 脚本和控制台中的安全变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28264871/