3

我正在制作一个小部件,其中包含一段代码,以放入您的网站,然后通过 js 拉入内容。这是一个示例片段:

<div data-token="bc1cea6304e8" id="my-widget">
    <script src="http://localhost:8080/assets/eg-widget.js" type="text/javascript"></script>
</div>

我正在做一个测试来检查页面是否已经有 jQuery,如果有,版本至少是 1.5。

if (typeof jQuery == 'undefined' || isVersion("1.5", ">")) {

    var script_tag = document.createElement('script');
    script_tag.setAttribute("type", "text/javascript");
    script_tag.setAttribute("src",
        "http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js");

    // Try to find the head, otherwise default to the documentElement
    (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);

    if (script_tag.readyState) {
        script_tag.onreadystatechange = function () { // For old versions of IE
            if (this.readyState == 'complete' || this.readyState == 'loaded') {
                scriptLoadHandler();
            }
        };
    } else { // Other browsers
        script_tag.onload = scriptLoadHandler;
    }
} else {
    // The jQuery version on the window is the one we want to use
    jQueryEg = window.jQuery;
    scriptLoadHandler();
}

在任何一种情况下,我们都将变量 jQueryEg 设置为我们决定使用的 jQuery,这样我们就可以避免冲突。

如果 jQuery 尚未加载,那么一切都是花花公子。但是如果加载了旧版本,我们在尝试加载其他库(如 jQuery-ui)时会遇到冲突。

为此,我们将 window.jQuery 设置为新加载的 jQuery,以便在加载 jquery-ui 和 bootstrap.js 时,它们对 window.jQuery 或 $ 的引用指向正确的版本。

问题是有时页面的其他部分在我们将 window.jQuery 设置为我们的版本的同时调用 jQuery,这会导致问题。

关于我们如何避免这些冲突的任何想法?

jQueryEg = window.jQuery.noConflict(true);
window.jQueryEg = jQueryEg;

// jquery-ui reference window.jQuery so we need to set that to our new jquery for a sec

if (jQueryEg.ui == undefined || jQueryEg.ui.datepicker == undefined) {
    var otherjQuery = window.jQuery;
    window.jQuery = jQueryEg;

    var script_tag = document.createElement('script');
    script_tag.setAttribute("type", "text/javascript");
    script_tag.setAttribute("src",
        "//ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js");
    (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);

    script_tag.onload = function () {
        window.jQuery = otherjQuery;
        main();
    };

}
4

2 回答 2

5

一旦我遇到类似的问题。查看 jQuery-UI 代码,我注意到它全部封装在一个立即调用的函数表达式中(或者我自己封装了它?我不记得了):

( function ( jQuery, undefined ){
  // Code here...
})( jQuery );

创建私有范围。所以我的解决方案是

  1. 将当前保存jQueryjQuery_OLD
  2. 加载新的 jQuery 版本
  3. 加载jQuery-UI,让它抓取兼容版本
  4. 恢复旧jQuery

所以下面给出了这个想法

<script src="jquery-1.4.js"></script>
<script>
    var jQuery_1_4 = jQuery.noConflict();
</script>
<script src="jquery-1.8.js"> </script>
<!-- load jquery UI -->
<script src="jquery-ui.js"> </script>
<!-- restore window.jQuery -->
<script>
    jQuery = jQuery_1_4;
</script>
于 2012-09-29T17:38:39.843 回答
1

之前遇到过这种确切的情况,最终的决定是您可能已经知道并且不想听到的:在加载这样的多个外部库版本时,根本没有避免所有边缘情况的好方法,由于您已经指定的原因。所涉及的并发症总结如下:

  • 当然,主要问题是:外部脚本的加载本质上是异步的,并且没有“执行前”/“执行后”回调来确保所有内容都被很好地包装。即:没有办法“包围”动态加载的代码。
  • 脚本在直接放置在文档中时按顺序执行,但无法根据另一个确定的内容有条件地加载一个脚本。
  • 最后,出于用户友好的原因(即:允许网络上的随机人员在零代码知识和没有支持人员的情况下使用您的代码段),诸如“确保将此代码段粘贴任何其他脚本之前!”之类的限制。是正确的。即使他们可以工作(*他们不会,真的看到其他两点),他们也会被忽略,尤其是那些不能完全控制他们的页面的人。

不幸的是,唯一的答案是显而易见的:在您自己的服务器上托管库的修改版本。

当然,您不需要一直提供这些版本,因此您仍然可以从使用 Google 的 CDN 中受益。同时,您仍然可以使用自己的 CDN 来交付修改后的版本。要遵循的主要准则是:

  1. 在整个页面加载后运行您的脚本(使用 onDOMReady 等),以确保在包含您自己的脚本“之后”不会发生冲突。
  2. 确定是否可能发生冲突。在这些情况下提供您的修改版本,否则从公共 CDN 提供。
  3. 经常检查与其他库的兼容性。您的代码会随着时间的推移而发展,就像您使用的库一样。“确定是否可能发生冲突”步骤需要准确才能使其正常工作。请谨慎行事:如果您不确定,请提供您自己的版本。
  4. 始终为粘贴者提供一个简单的选项,说“始终使用修改后的版本”,以防您的检测以某种方式失败。
  5. 始终提供带有适当缓存标头的脚本的压缩丑化版本,以减少您自己的服务器上的负载。

相对而言,您通常会发现您自己的服务器上的点击次数实际上非常少。一如既往,不要相信我:在你自己的真实世界场景中保持统计数据!

于 2012-09-29T17:43:56.587 回答