【问题标题】:Correct way of loading non-AMD compatible jQuery plugins in require.js with jQuery in noConflict mode?在 noConflict 模式下使用 jQuery 在 require.js 中加载非 AMD 兼容的 jQuery 插件的正确方法?
【发布时间】:2013-01-07 04:26:08
【问题描述】:

假设我想将 jquery 与使用标准闭包定义的标准、非 amd 启用 jquery 插件一起使用:(function($))( $.fn.myplugin = { ... } )(jQuery);,它都位于 js/libs/jquery/jquery.myplugin.js 内。

我使用这个配置:

require.config({
  baseUrl: 'js/',
  paths: {
    'jquery':          'libs/jquery/jquery-noconflict', 
    'underscore':      'libs/underscore/underscore',
    'backbone':        'libs/backbone/backbone',
    'jquery-myplugin': 'libs/jquery/jquery.myplugin'
  },
  shim: {
    'backbone': {
      deps: ['underscore', 'jquery'],
      exports: 'Backbone'
  },
  'jquery-myplugin': {
    deps:  ['jquery'] 
  }
});

我在libs/jquery/jquery-noconflict.js 中以无冲突模式加载 jQuery,因为我不想污染全局命名空间:

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

这就是我加载主 app.js 的方式:

define([
  'jquery',
  'underscore',
  'backbone',
  'jquery-myplugin'],
function($, _, Backbone, MyPlugin){
  //MyPlugin is always undefined, not even sure if 
  //I should be passing it here if it only extends jQuery?
});

现在,这是我遇到的问题 - 虽然我可以毫无问题地使用上面定义的所有库,但我无法计算出正确的 shim 配置来加载非 AMD 启用的 jquery 插件。

我尝试将 jquery-myplugin 设置为 depsjquery(以及其他方式),但我永远无法让它工作。

我似乎在以下情况下遇到问题:

  1. jQuery 以无冲突模式加载。
  2. 插件代码运行,扩展上面的jQuery实例
  3. 我可以在我的应用程序中使用由插件代码扩展的 $,因此 $.myplugin 可用。

我看到过类似的问题,但没有一个能真正解决这个问题,只给出了模糊的建议,例如“使用 shim config”...

编辑

我也尝试过使用

"jquery-myplugin": {
    deps: ["jquery"],
    exports: "jQuery.fn.myplugin"
}

虽然通过这种方式加载为 AMD 模块后插件方法可用,但我仍然无法访问:$('.class').myplugin(),因为默认 $ 对象尚未使用 myplugin 代码进行扩展。

【问题讨论】:

  • 您还有这个问题吗?
  • 模块依赖关系应该用数组表示:define(['dep1', 'dep2'...'depn'], function(dep1, dep2, ...depn){});,如here所述
  • 很好,但这只是我在 stackoverflow 上的错误输入,根本问题仍然存在

标签: requirejs amd


【解决方案1】:

使用jQuery.noConflict(true) 删除jQuery 全局变量。当您的插件加载时,它会尝试访问jQuery,但无法访问,导致此失败。

如果您的插件是一个模块,它可以作为依赖项访问 jQuery。或者您可以将jQuery 保留为全局可用。

【讨论】:

  • 谢谢肖恩,我知道这里会发生什么,我想做的是正确使用 require.js ,其中所有模块都不应创建全局变量,所有其他模块都将 jQuery 作为依赖项加载(如果需要) .
  • 如果是这种情况,您将无法使用未转换的插件。如果您希望 jQuery 仅作为模块可用,那么您必须将插件转换为使用 define(),以便声明对 jQuery 的依赖。
  • 感谢 Sean,我的印象是 shim 配置仍然允许您在不使用全局依赖项的情况下处理未启用 AMD 的模块。恕我直言,您必须修改第 3 方代码才能使其与 AMD/require 一起使用,这很浪费时间。
  • Shim 可让您将纯脚本转换为模块,但它不会让您了解依赖项。如果您将 jQuery 保留为全局,它会解决的。遗憾的是,第 3 方的东西不适用于 AMD。当 jQuery 采用它时,我寄予厚望。当 Backbone 删除它时,很明显我们不会很快看到大规模采用。
【解决方案2】:

首先,确保“path/to/jquery-myplugin”实际上扩展了window.jQuery 而不是$

noConflict() 保留 window.jQuery 对象已定义,但从 window.$ 解除绑定在一些新浏览器上,window.$ 内置了本机 document.querySelectorAll 函数的别名。

其次,你的 myplugin 不需要自己返回,因为它不能被自己使用。因为它扩展了 jQuery,所以从 myplugin 调用返回 jQuery。

最后,“path/to/jquery-myplugin”不是模块。这是一个普通的 JS 文件。有可能 RequireJS 尝试像模块一样加载它并且找不到 define() 调用,这会导致混乱。尝试将“.js”文件扩展名添加到引用中,以向 RequireJS 发出它需要使用“js!”的信号。加载资源的插件。

require.config({
    paths: {
        "jquery": "path/to/jquery",
        "jquery-myplugin": "path/to/jquery-myplugin.js"
    },
    shim: {
        "jquery": {
          init: function() {
             return window.jQuery.noConflict();
          },
        "jquery-myplugin": {
          deps: ['jquery']
          init: function($) {
             return $;
          },
       }
    } 
});

【讨论】:

  • 那是错误的。 noConflict 的代码在这里:javascript noConflict: function( deep ) { if ( window.$ === jQuery ) { window.$ = _$; } if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; } return jQuery; }, 当您传递“deep”参数时,它也会取消绑定 window.jQuery,因此您可以在同一页面上运行多个版本。
【解决方案3】:

我今天遇到了和你一样的问题。这是我可以解决的方法:

requirejs.config({
    "baseUrl": "js/lib",
    "paths": {
      "app": "../app"
    }
});

// Final version of jQuery with all needed plugins.
define("jquery", ["jquery-core", "myplugin"], function(jqCore) {
    return jqCore;
});

// Define core jQuery module.
define("jquery-core", ["jquery-1.9.1.min"], function() {
    return jQuery.noConflict(true);
});

// This module exposes jquery module to the global scope and returns previous defined version.
define("jq-global", ["jquery-core"], function(jqCore) {
    var tmp = jQuery;
    jQuery = jqCore;
    return tmp;
});

// Define your plugin here, and don't forget to reset previous jQuery version.
define("myplugin", ["jq-global", "jquery.myplugin"], function(jqGlobal, jqPlugin) {
    jQuery = jqGlobal;
});

// Load the main app module to start the app
requirejs(["app/main"]);

现在在我的 app/main.js 文件中,我可以执行以下操作:

define(["jquery"], function($) {
    $('body').myplugin();
});

这里的想法是在插件代码执行之前临时暴露 jQuery。到目前为止,我还没有在需要加载更多模块的更大环境中测试该解决方案,所以我不能保证它会长期工作;)

编辑

这个解决方案行不通!!由于 requirejs 不会按顺序加载脚本,因此插件 js 文件可能在 jquery 之前加载,这将导致执行失败。对此感到抱歉。

如果有人有其他想法...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-14
    • 1970-01-01
    • 2015-10-18
    • 1970-01-01
    • 1970-01-01
    • 2012-11-11
    • 2016-02-26
    相关资源
    最近更新 更多