我如何一起使用requireJS和jQuery?

我想使用requireJS,我正在使用jQuery。 我不想使用requireJS和jQuery的组合版本,因为我没有使用最新的jQuery版本。 我需要使用requireJS的最佳方式是什么?

这也是我的确切问题! 我也必须使用一个较老的jQuery,但也更“传统”的JavaScript库。 什么是最好的技术来做到这一点? (如果你不介意的话,我可以编辑你的问题,使其更广泛。)这是我学到的。

RequireJS作者James Burke解释了RequireJS + jQuery文件的优点 。 你有两件事

  1. 一个模块, jquery ,可用,它是jQuery对象。 这是安全的:

     // My module depends on jQuery but what if $ was overwritten? define(["jquery"], function($) { // $ is guaranteed to be jQuery now */ }) 
  2. 在任何require()define()东西之前,jQuery已经被加载了。 所有模块都保证jQuery已经准备就绪。 你甚至不需要require/order.js插件,因为jQuery基本上是硬编码加载的。

对我来说,#2是不是很有帮助。 大多数真正的应用程序都有许多 .js文件,它们必须以正确的顺序加载 – 令人伤心但真实。 只要你需要Sammy或Underscore.js,合并的RequireJS + jQuery文件就没有帮助。

我的解决scheme是编写简单的RequireJS包装,使用“order”插件加载我的传统脚本。

假设我的应用程序有这些组件(依赖)。

  • 我的应用程序, greatapp
    • greatapp取决于一个自定义的jquery (旧版本我必须使用)
    • greatapp取决于my_sammy (SammyJS加上我必须使用的所有插件)。 这些必须是有序的
      1. my_sammy取决于jquery (SammyJS是一个jQuery插件)
      2. my_sammy取决于sammy.js
      3. my_sammy取决于sammy.json.js
      4. my_sammy取决于sammy.storage.js
      5. my_sammy取决于sammy.mustache.js

在我看来,以.js结尾的所有内容都是一个“传统”的脚本。 没有.js东西是一个RequireJS插件。 关键是:高层次的东西(greatapp,my_sammy)是模块,在更深层次上,它回落到传统的.js文件中。

引导

这一切都始于一个booter告诉RequireJS如何开始。

 <html> <head> <script data-main="js/boot.js" src="js/require.js"></script> </head> </html> 

js/boot.js我只把configuration和如何启动应用程序。

 require( // The "paths" maps module names to actual places to fetch the file. // I made modules with simple names (jquery, sammy) that will do the hard work. { paths: { jquery: "require_jquery" , sammy : "require_sammy" } } // Next is the root module to run, which depends on everything else. , [ "greatapp" ] // Finally, start my app in whatever way it uses. , function(greatapp) { greatapp.start(); } ); 

主要应用

greatapp.js我有一个正常的模块。

 define(["jquery", "sammy"], function($, Sammy) { // At this point, jQuery and SammyJS are loaded successfully. // By depending on "jquery", the "require_jquery.js" file will run; same for sammy. // Those require_* files also pass jQuery and Sammy to here, so no more globals! var start = function() { $(document).ready(function() { $("body").html("Hello world!"); }) } return {"start":start}; } 

RequireJS模块包装传统文件

require_jquery.js

 define(["/custom/path/to/my/jquery.js?1.4.2"], function() { // Raw jQuery does not return anything, so return it explicitly here. return jQuery; }) 

require_sammy.js

 // These must be in order, so use the "order!" plugin. define([ "order!jquery" , "order!/path/to/custom/sammy/sammy-0.6.2-min.js" , "order!/path/to/custom/sammy/plugins/sammy.json-0.6.2-min.js" , "order!/path/to/custom/sammy/plugins/sammy.storage-0.6.2-min.js" , "order!/path/to/custom/sammy/plugins/sammy.mustache-0.6.2-min.js" ] , function($) { // Raw sammy does not return anything, so return it explicitly here. return $.sammy; } ); 

这个问题现在至less有两年了,但是我注意到RequireJS 2.0仍然存在问题(require-jquery.js使用jQuery 1.8.0,但是最新版本是1.8.2)。

如果碰巧看到这个问题,请注意, require-jquery.js现在只是require.js和jquery.js,混合在一起。 您可以编辑require-jquery.js,并用新版本replacejQuery部分

更新(2013年5月30日) :既然RequireJS有path和填充,现在有一种新的方法来导入jQuery和jQuery插件,旧的方法不再需要也不推荐 。 以下是当前方法的删节版本:

 requirejs.config({ "paths": { "jquery": "//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min" } }); define(["jquery"], function($) { $(function() { }); }); 

有关更多信息,请参阅http://requirejs.org/docs/jquery.html

我发现最好的方法是让我的RequireJS版本以外的jQuery。

只需在您的HTML中包含jquery.min.js。 然后,用这样的东西做一个jquery.js文件…

 define([], function() { return window.$; }); 

发现JasonSmith的工具非常有帮助,可能比RequireJS的文档更重要。

但是,有一种方法可以对其进行优化,以避免对(微小)定义声明模块(“require_jquery”“require_sammy”)单独的AJAX请求。 我会怀疑r.js会在优化阶段这样做,但是你可以提前做,以免与Path,BaseURI系统打架。

index.html的:

 <html> <head> <script data-main="js/loader.js" src="js/require.js"></script> </head> </html> 

loader.js:

 // We are going to define( dependencies by hand, inline. // There is one problem with that through (inferred from testing): // Dependencies are starting to load (and execute) at the point of declaring the inline // define, not at the point of require( // So you may want to nest the inline-defines inside require( // this is, in a way, short replacement for Order plug in, but allows you to use // hand-rolled defines, which the Order plug in, apparently does not allow. var jQueryAndShims = ['jquery'] if(window.JSON == null){ jQueryAndShims.push('json2') define( 'json2' , ['js/libs/json2.min.js'] , function() { return window.JSON } ) } // will start loading the second we define it. define( 'jquery' , ['js/libs/jquery_custom.min.js'] , function() { // we just pick up global jQuery here. // If you want more than one version of jQuery in dom, read a more complicated solution discussed in // "Registering jQuery As An Async-compatible Module" chapter of // http://addyosmani.com/writing-modular-js/ return window.jQuery } ) // all inline defines for resources that don't rely on other resources can go here. // First level require( // regardless of depends nesting in 'myapp' they will all start downloading // at the point of define( and exec whenever they want, // async in many browsers. Actually requiring it before the nested require makes // sure jquery had *executed and added jQuery to window object* before // all resolved depends (jquery plugins) start firing. require(jQueryAndShims, function($) { // will start loading the second we define it. define( 'sammy_and_friends' , ['jquery','js/libs/jquery_pluginone.min.js','js/libs/jquery_plugintwo.min.js','js/libs/sammy.min.js'] , function($) { // note, all plugins are unaltered, as they are shipped by developers. // in other words, they don't have define(.. inside. // since they augment global $ (window.jQuery) anyway, and 'jquery' define above picks it up // , we just keep on returning it. // Sammy is attached to $ as $.sammy, so returning just Sammy makes little sense return $ } ) // second level require - insures that Sammy (and other jQuery plugins) - 'sammy_and_friends' - is // loaded before we load Sammy plugins. I normally i would inline all sammy plugins i need // (none, since i use none of them preferring jQuery's direct templating API // and no other Sammy plug in is really of value. ) right into sammy.js file. // But if you want to keep them separate: require(['sammy_and_friends'], function() { // will start loading the second we define it. define( 'sammy_extended' , ['sammy_and_friends','js/libs/sammy_pluginone.min.js','js/libs/sammy_plugintwo.min.js'] , function($) { // as defined above, 'sammy_and_friends' actually returns (globall) jQuery obj to which // Sammy is attached. So we continue to return $ return $ } ) // will start loading the second we define it. define( 'myapp' , ['sammy_extended', 'js/myapplication_v20111231.js'] , function($, myapp_instantiator) { // note, myapplication may, but does not have to contain RequireJS-compatible define // that returns something. However, if it contains something like // "$(document).ready(function() { ... " already it MAY fire before // it's depends - 'sammy_extended' is fully loaded. // Insdead i recommend that myapplication.js returns a generator // (app-object-generating function pointer) // that takes jQuery (with all loaded , applied plugins) // The expectation is that before the below return is executed, // all depends are loaded (in order of depends tree) // You would init your app here like so: return myapp_instantiator($) // then "Run" the instance in require( as shown below } ) // Third level require - the one that actually starts our application and relies on // dependency pyramid stat starts with jQuery + Shims, followed by jQuery plugins, Sammy, // followed by Sammy's plugins all coming in under 'sammy_extended' require(['jquery', 'myapp'], function($, myappinstance) { $(document).ready(function() {myappinstance.Run()}) }) }) // end of Second-level require }) // end of First-level require 

最后,myapplication.js:

 // this define is a double-wrap. // it returns application object instantiator that takes in jQuery (when it's available) and , then, that // instance can be "ran" by pulling .Run() method on it. define(function() { // this function does only two things: // 1. defines our application class // 2. inits the class and returns it. return function($) { // 1. defining the class var MyAppClass = function($) { var me = this this._sammy_application = $.sammy(function() { this.raise_errors = true this.debug = true this.run_interval_every = 300 this.template_engine = null this.element_selector = 'body' // .. }) this._sammy_application.route(...) // define your routes ets... this.MyAppMethodA = function(blah){log(blah)} // extend your app with methods if you want // ... // this one is the one we will .Run from require( in loader.js this.Run = function() { me._sammy_application.run('#/') } } // 2. returning class's instance return new MyAppClass($) // notice that this is INITED app, but not started (by .Run) // .Run will be pulled by calling code when appropriate } }) 

这个结构(松散地replace(重复?)RequireJS的Order插件,但是)允许你修剪你需要的AJAX文件的数量,增加更多的控制来定义依赖和依赖树。

单独加载jQuery(通常是100k)也有很大的好处 – 你可以控制服务器的caching,或者把jQuerycaching到浏览器的localStorage中。 看看这里的AMDcaching项目https://github.com/jensarps/AMD-cache然后改变定义(声明包括“caching!”:它将(永远;:))卡在用户的浏览器。

 define( 'jquery' , ['cache!js/libs/jquery_old.min.js'] , function() { // we just pick up global jQuery here. // If you want more than one version of jQuery in dom, read a more complicated solution discussed in // "Registering jQuery As An Async-compatible Module" chapter of // http://addyosmani.com/writing-modular-js/ return window.jQuery } ) 

关于jQuery 1.7.x +的注意事项它不再将自己附加到窗口对象,所以以上将不会使用未修改的jQuery 1.7.x +文件。 你必须定制你的jquery **。js在结束之前包含这个}}(window);“:

 ;window.jQuery=window.$=jQuery 

如果你在控制台中有“jQuery未定义”的错误,那么你正在使用的jQuery版本并没有将自己附加到窗口上。

代码许可证:公共领域。

披露:JavaScript以上的“伪代码”的味道,因为它是一个更详细的生产代码的释义(手修剪)。 上面提供的代码不能保证能够正常工作,也没有经过testing才能按照提供的方式工作 审计,testing它。 分号特意省略了,因为它们不是每个JS规范和代码都要求的,没有它们,看起来更好。

除了jhs的回答之外,请参阅README.md文件中有关require-jquery github页面的更新指令。 它涵盖了使用组合jquery / require.js文件的最简单方法,以及如何使用单独的jquery.js。