jQuery 没有冲突,bootstrap 和 requirejs

jQuery noconflict, bootstrap and requirejs

我正在开发的环境正在使用 jQuery 1.7.1,而我需要专门使用 jQuery 2.1.3。但是当我使用 2.1.3 时,一些遗留代码中断(因为它使用 1.7.1)所以我不得不在 2.1.3

上使用 jQuery.noconflict

jquery-private.js:

define(["jquery"], function(jQuery){
    return jQuery.noConflict(true);
});

所以在我的 requirejs 配置文件中我有这个:

config.js:

requirejs.config({
    baseUrl: '../',
    paths: {
        'jquery': 'js/jquery/jquery',
        'jqueryui': 'js/jquery-ui/jquery-ui',
        'bootstrap': 'js/bootstrap',
    },
    map: {
        // '*' means all modules will get 'jquery-private'
        // for their 'jquery' dependency.
        '*': {
            'jquery': 'jquery-private'
        },

        // 'jquery-private' wants the real jQuery module
        // though. If this line was not here, there would
        // be an unresolvable cyclic dependency.
        'jquery-private': {
            'jquery': 'jquery'
        }
    },
    shim: {
        'bootstrap': {
            deps: ['jquery']
        }
    }
});

所以当我需要bootstrap

widget.js:

require([
    "jquery",
    "bootstrap"
], function(jqr){
    // SOME CODE
});

我得到一个错误:

未捕获错误:Bootstrap 的 JavaScript 需要 jQuery 版本 1.9.1 或更高版本

所以 bootstrap 正在选择 1.7.1。

如何在不更改 bootstrap.js 文件的情况下使其获取 2.1.3?

为什么会失败?

您当前的尝试无法成功,因为您的 jquery-private 设置确保一旦 jQuery 作为 RequireJS 模块加载,就会调用 noConflict()。只要用 RequireJS 加载的代码通过 define 调用(例如 define(['jquery'], function ($) {)引用 jQuery 就没有问题。但是,填充的任何代码都将引用 $jQuery 全局变量,因此将引用版本 1.7.1.

一个解决方案

没有任何其他约束,首选解决方案是让整个代码库使用相同的 jQuery 版本。将 1.7.1 升级到 1.x 系列中的最新版本,然后使用它。根据 download page,2.x 和 1.x 系列中相对较新的版本之间没有 API 区别(我会说 1.9.x 和更高版本).当然,这意味着依赖于 1.7.1 的代码可能必须更新才能与 1.x 系列中的最新 jQuery 一起使用。

我建议升级到 2.x 系列,但您在评论中提到需要与 IE 6 和 7 兼容。请注意:如果您设法加载 1.7.1 和 2.1.3同一页面,使用 2.1.3 的那部分代码不会与 IE 6 和 7 兼容,因此该页面实际上不再与 IE 6 和 7 兼容。

要使用此解决方案,除了升级必须进行的更改外,您还必须:

  1. 确保 jQuery 在 之前加载 RequireJS。否则,它会检测到 RequireJS 并调用 define 但随后它不会 可靠地 可用于未加载 RequireJS 的代码。 (我说它不会是 "reliably available" 因为虽然一旦 jquery 模块被加载,然后 jQuery$ 全局变量将存在,问题是代码是未加载 RequireJS 无法等待 以加载 RequireJS jQuery。因此,除非您煞费苦心地编写自己的同步代码,否则它不会可靠地工作。)

  2. 创建一个 RequireJS 模块,它仅使在 RequireJS 模块之前加载的 jQuery 作为一个模块可用于 RequireJS 模块,因此:

    define('jquery', function () { return jQuery; });
    

    这可以放在您致电 require.config 之前。这将创建一个 "fake" jquery 模块,它只是 return 全局 jQuery 符号。 (也可以 return $。)

备选方案?

我没有看到 robust 上述解决方案的替代方案。提出可以证明另一种方法的概念证明并不难。但是,一旦您尝试在实际项目中使用它,它就会失败。问题是 RequireJS 本质上是异步的,所以你不能开始弄乱 $jQuery 全局变量来按照你想要的方式设置它们并确保你想要发生的一切都会发生 在您希望它发生的时间。此外,在 RequireJS 之前加载的任何代码恰好启动异步操作,而异步操作可能与 RequireJS 的模块加载交错发生,这会给整个操作带来麻烦。我宁愿避免提出一旦从概念验证到实际应用就会失败的解决方案。