如何使一个 jQuery 插件可以在 requirejs 中加载

88

我正在使用requirejs + jquery,想知道是否有一个聪明的方法使jQuery插件与require兼容。

例如,我正在使用jQuery-cookie。 如果我理解正确,我可以创建一个名为jquery-cookie.js的文件,并在其中执行以下操作:

define(["jquery"], // Require jquery
       function($){
// Put here the plugin code. 
// No need to return anything as we are augmenting the jQuery object
});
requirejs.config( {
    "shim": {
        "jquery-cookie"  : ["jquery"]
    }
} );

我想知道是否可以像jQuery那样做事情,就像这样:

if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
    define( "jquery", [], function () { return jQuery; } );
}

如果这是使jQuery插件与requirejs或任何amd兼容的唯一方法

3个回答

104

在使用RequireJS的shim配置时,有一些需要注意的地方,可以在http://requirejs.org/docs/api.html#config-shim上找到。 特别是,在使用优化器时,“不要将CDN加载与shim配置混合在一起进行构建”。

我正在寻找一种方法,在既有RequireJS又没有RequireJS的网站上都可以使用相同的jQuery插件代码。 我在https://github.com/umdjs/umd/blob/master/jqueryPlugin.js上找到了这个jQuery插件片段。 只需将您的插件放入此代码中,它就可以正常工作。

(function (factory) {
if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module depending on jQuery.
    define(['jquery'], factory);
} else {
    // No AMD. Register plugin with global jQuery object.
    factory(jQuery);
}
}(function ($) {

    $.fn.yourjQueryPlugin = function () {
        // Put your plugin code here
    };  

}));

感谢jrburke的贡献;像很多javascript一样,它是函数内嵌函数并作用于其他函数。但我认为我已经理解了它的功能。

第一行中的函数参数factory本身就是一个函数,它被调用来在$参数上定义插件。当没有AMD兼容的加载器时,它直接被调用以在全局jQuery对象上定义插件。这就像常见的插件定义习语一样:

function($)
{
  $.fn.yourjQueryPlugin = function() {
    // Plugin code here
  };
}(jQuery);

如果有一个模块加载器,那么 factory 就会被注册为加载器回调函数,在加载 jQuery 后调用。已加载的 jQuery 是参数。这相当于:

如果存在模块加载器,则将 factory 注册为加载程序在加载 jQuery 后调用的回调。已加载的 jQuery 是该回调的参数。这等同于:

define(['jquery'], function($) {
  $.fn.yourjQueryPlugin = function() {
     // Plugin code here
  };
})

3
我喜欢这个答案,因为即使问题是关于 jQuery 插件的,它也适用于任何类型的模块或库,而不仅仅是 jQuery。我花了一分钟来理解你的代码,但一旦我理解了,它就很清晰易懂了。 - Adam Tuttle
1
这绝对是无法穿透的 JavaScript。我添加了一些关于它如何工作的解释。 - Carl Raymond
哇,我很久以前就想了解这段代码片段了。非常感谢! shim 实质上就是在做这件事吗?我猜不是...因为你说你正在手动编写它,就像上面那样。 - eugene
对于像我这样的白痴,专业提示:在代码片段中看到 $.fn.jqueryPlugin 的地方,将 jqueryPlugin 更改为插件名称! - Matt Lacey
我将属性名称更改为yourjQueryPlugin,以使您的jQuery插件放置位置更清晰。 - Carl Raymond
显示剩余2条评论

67

你只需要做其中一种

define(["jquery"], // Require jquery
       function($){
// Put here the plugin code. 
// No need to return anything as we are augmenting the jQuery object
});
在jquery-cookie.js的末尾,或者
requirejs.config( {
    "shim": {
        "jquery-cookie"  : ["jquery"]
    }
} );

无论何时在包含jquery-cookie之前都可以(例如,无论数据主要指向哪里)。

你发布的最后一个代码块适用于像jQuery这样的东西,它们会被重新分发,可能处于AMD环境中也可能不是。理想情况下,每个jQuery插件都应该已经设置好了这个。

我更喜欢保持包含的库尽可能原始,因此全局shim配置每页一次似乎对我来说是最清洁的解决方案。这样升级更加安全,CDN也变成了可能。


1
如果我不同时进行定义和shim操作,那么就会出现“$.cookie不是一个函数”的错误信息。 - Nicola Peluchetti
根据我的经验,从定义函数中不返回任何内容是不够的,RequireJS 将无法识别模块已加载。可以通过以下方式解决:shim: { plugins : { depends: ['jquery'], exports: 'plugins' } - honzajde
你应该注意到jQuery插件脚本需要实际运行。虽然我不是专家,但我找到了一个简单的解决方案,其中你只需要一个require(['plugin1', 'plugin2']);等。没有传递回调函数,因此除了插件脚本本身之外,什么都不会运行。这意味着它们将添加到jQuery.fn中,因此在其他地方,您可以只列出'jquery'作为依赖项,它们就会被包含。就像我说的,我对这个还比较新手,可能有更好的方法(例如只使用script标签),但是这样确实可行。 - Joshua Bambrick
3
Josh:你正在赌注一切都会按正确的顺序加载,您的网站上的一些用户可能会看到错误的内容。问题不是插件加载的多少,而是插件加载的时间以及同时执行的其他操作。使用“require”的主要原因是基于依赖关系确保操作的合理顺序,而不是靠猜测。 - Hans

2

提醒大家一下,一些jQuery插件已经使用了AMD/Require,因此您不需要在Shim中声明任何内容。事实上,在某些情况下这样做可能会给您带来问题。

如果您查看jquery cookie JS,您将看到define调用和require(["jquery"])。

而在jquery.js中,您将看到一个对define("jquery",[],function()...的调用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接