RequireJS 创建对象副本的方法

RequireJS way of creating a copy of object

我们的项目非常庞大,单页企业应用程序,基于 RequireJS 和 Backbone.js,对于一些复杂的 UI 我们使用 jqWidgets

特别是这些 jqWidgets 是导致我们出现问题的原因。 有许多应用程序功能使用较旧的 jqWidgets 3.3 实现,对于所有新功能,我们希望使用 3.6,但是将旧功能移植到 3.6 非常棘手,并且会花费我们目前没有的时间。

为了节省时间,我们想做的是让 3.3 和 3.6 一起工作而不产生任何问题,然后在我们可以的时候再做移植部分。

到目前为止我尝试过的:

requirejs.config({
    paths: {
        "jquery": "vendor/jquery",
        "jqx": "vendor/jqwidgets/3.3",
        "jqx3.6": "vendor/jqwidgets/3.6",
        ... other libs...
    },
    shim: {
        ... other shims ...
        // jqWidgets3.3
        "jqx/jqxcore": {
             deps: ["jquery"]
        },
        "jqx/<<some_plugin>>": {
             deps: ["jqx/jqxcore"],
             exports: "$.fn.<<some_plugin>>"
        },
        // jqWidgets3.6
        "jqx3.6/jqxcore": {
             deps: ["jquery"]
        },
        "jqx3.6/<<some_plugin>>": {
             deps: ["jqx3.6/jqxcore"],
             exports: "$.fn.<<some_plugin>>"
        },
    }
});

旧功能中的用法:

require(["jquery", "jqx/<<some_plugin>>"], function($) {
     $('<<some_selector>>').<<some_plugin>>(...options...);
});

新功能中的用法:

require(["jquery", "jqx3.6/<<some_plugin>>"], function($) {
     $('<<some_selector>>').<<some_plugin>>(...options...);
});

因为这两个插件都应用于相同的 jQuery 对象,所以用不同的 names/paths 引用它们可以工作,但会产生很多错误。示例:如果您在应用程序中使用的第一个功能是使用 jqWidgets 3.3 加载的,那么下一个使用 3.6 的功能可能会损坏,反之亦然。仅当您在每次使用功能后刷新页面时它才有效——这有点毫无意义,因为它是单页应用程序。

所以我的问题是:是否可以让 jqWidgets 3.3 和 3.6 同时工作,然后每个都依赖于它们自己的 jQuery 对象,这样就不会发生这种冲突?

// 附录一: 我认为潜在的解决方案在于对这个问题的评论:RequireJS - jQuery plugins with multiple jQuery versions 我会仔细查看,post 如果找到解决方案,我会在此处提供解决方案。

如果 jqWidgets 不支持开箱即用,我会试试这个:

  • 加载jQuery
  • 加载jqxWidget 3.3
  • 再次加载 jQuery ,但在其无冲突模式下,并将其分配给 </code> 例如(我不确定 RequireJS 是否可以做到这一点,但您可以复制 jQuery.js 文件并将其重命名为不同的名称以便第二次加载它)</li> <li>将第一个 jQuery 设置为 $1 (<code>window. = $)
  • 设置第二个jQuery为$(window.$ = )
  • 加载jqxWidget 3.6

现在每个 jqxWidget 都应该有自己的、独立的 jQuery。 显然 jQuery 加载两次并不理想,但除了在您的应用程序上使用更多内存外,这应该不是问题。

你可以使用 requirejs 的 'map' 功能, Map 允许您根据使用依赖项的模块将相同的依赖项映射到不同的文件。 所以你像这样配置你的构建文件:

requirejs.config({
    paths: {
        "jquery": "vendor/jquery",
        "jqueryForjqx3.6": "toNoConflictJQueryModule",
        "jqx": "vendor/jqwidgets/3.3",
        "jqx3.6": "vendor/jqwidgets/3.6",
    ... other libs...
    },
    map:{
        '*':{
             .....
        },
        'jqx':{
            'jquery' : 'jquery'
        },
        'jqx3.6':{
             // map jquery to no conlict jquery
            'jquery' : 'jqueryForjqx3.6'
        },
        'jqueryForjqx3.6':{
            'jquery' : 'jquery'
        }
    },
    shim: {
        ... other shims ...
        // jqWidgets3.3
        "jqx/jqxcore": {
             deps: ["jquery"]
        },
        "jqx/<<some_plugin>>": {
             deps: ["jqx/jqxcore"],
             exports: "$.fn.<<some_plugin>>"
        },
        // jqWidgets3.6
        "jqx3.6/jqxcore": {
             deps: ["jquery"]
        },
        "jqx3.6/<<some_plugin>>": {
             deps: ["jqx3.6/jqxcore"],
             exports: "$.fn.<<some_plugin>>"
        },
    }
});

此配置根据使用它的模块将 jquery 依赖项映射到不同的文件。

无冲突版本的内容可以是这样的:

define(['jquery'], function($){
    return $.noConflict();
});

你可以使用http://requirejs.org/docs/jquery.html#noconflictmap了解如何使用jquery no-conflict和requirejs