我有一个包含以下内容的用户脚本:
// userscript header
(function() {
// here is jquery source code
var $ = $.noConflict();
})();
我正在使用它的网站正在使用 mootools,因此该网站的代码取决于 $
。由于某些奇怪的原因,noConflict
在 Firefox (23.0.1) 中没有帮助。该网站仍然以 $ 形式获取 jQuery,这破坏了网站的原始功能。
但是,当我将其更改为: var $ = jQuery.noConflict();
它有效。为什么?
我无法将用户脚本放在 jsfiddle 上,所以这里有一个包含所有代码的 gif(左侧是 HTML,右侧是用户脚本),显示了问题:
版本:一切都是最新的,Firefox 23.0.1、Greasemonkey 1.11、jQuery v1.10.2、Mootools 1.4.5-nc
“Bug”不会发生在:Chrome 29.0.1547.66m、Opera 12.16
最佳答案
让我们看看 noConflict()
是如何实际实现的...
if ( window.$ === jQuery ) {
window.$ = _$; // where $_ is window.$ before jquery reassigns it.
}
现在我们需要记住,用户脚本操作的窗口
实际上与站点看到的窗口
不同。它是一个沙盒包装器(至少在 Greasemonkey 和 Scriptish 中)。该包装器实际上隐藏了所有“expandos”,即在原始对象上添加或覆盖的属性。
因此,在您的用户脚本中 window.$ === undefined
而在实际页面中,它被定义为 mootools 助手。 unsafewindow.$
也是 mootools 助手,如 unsafeWindow
是展开的页面窗口
。
现在,当您的用户脚本包含 jQuery 时,$
将在包装的窗口
上设置。原来的页面window.$
从网站角度来看仍然是mootools。
接下来,对 .noConflict()
的调用(如上面实现的那样)将恢复 window.$
,但在沙箱包装器上。因此,用户脚本沙箱中的 window.$
再次变为 undefined
,而页面 window.$
(又名。unsafeWindow.$
在用户脚本沙箱中)仍然是 moo 助手(实际上从未改变)。
更新:Greasemonkey 在 createSandox()
的“no-grants”分支中显式主动禁用这些包装器通过设置 wantXRays = false
。我认为这是 a bug .
现在,这就是为什么您在 GM
中首先需要 .noConflict()
的原因。
var $ = $.noConflict()
无法工作,因为它是一个错误。 var $
将被提升,因此它立即成为未定义的。 jQuery 实际上不会设置它(它只是设置 window.$
,而不是本地范围 $
),因此 $.noConflict()
调用变为 undefined.noConflict()
。
关于jQuery.noConflict 用户脚本中的奇怪行为,仅在 Firefox 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18663650/