RequireJS与jQuery模块化开发实战:循环依赖与UI插件集成详解

作者:资源驿站

时间:2026-10-30

浏览:253

本文深入解析基于RequireJS和jQuery的模块化开发中遇到的核心问题。重点探讨AMD与CMD加载机制差异,详细演示如何通过延迟加载解决模块间的循环依赖报错。同时,针对jQuery UI及DataTables等插件在RequireJS环境下的兼容性问题,提供了修改源码以正确传入jQuery对象的具体解决方案,并给出了处理DOM重构后事件失效的实用技巧。

文章目录

RequireJS与jQuery模块化开发背景

随着前端JavaScript代码逻辑日益复杂,单个JS文件往往包含上千行代码,这给开发与维护带来了巨大挑战。近期在重构重型逻辑时,面对RequireJS与SeaJS的选择,最终倾向于使用RequireJS,主要因其官方文档更为专业完善。

尽管拥有完整的官方文档,在实际项目中仍会遇到诸多具体问题,例如jQuery UI插件的集成与使用。

下文将逐步梳理开发过程中遇到的典型问题及其对应的解决方案。

AMD与CMD规范对比

关于AMD和CMD的理解

AMD(异步模块定义)的代表实现是RequireJS,而CMD(通用模块定义)的典型代表则是淘宝的SeaJS。

两者的共同点在于均采用异步方式加载JS文件。但核心区别在于执行时机:RequireJS在模块加载完成后立即执行;而SeaJS则延迟执行,直到主函数调用该模块时才进行加载和执行。

若使用SeaJS,初始加载效率较高,但在后续使用中可能因即时执行JS代码而导致页面卡顿,影响用户体验(注:此观点基于理论分析,未经过实际大规模测试验证)。相比之下,RequireJS在初始化阶段即执行所有加载的JS模块,若模块中包含某些执行方法,其执行顺序可能并不完全符合预期。

因此,如果开发者已习惯异步编程模式,且看重完善的文档支持,推荐选用RequireJS;若对执行顺序有严格要求且追求开发便捷性,SeaJS也是可行的选择。

解决RequireJS循环依赖问题

如何解决requirejs中循环依赖问题

当模块a依赖模块b,而模块b又反过来依赖模块a时,就会触发循环依赖异常。

以下是一个具体的循环依赖示例。

主页面配置如下:


<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script data-main="test.js" src="lib/require.js"></script>
</body>
</html>

主入口函数定义:


requirejs.config({
  baseUrl: './'
});

requirejs(['js/a'],function (a){
  console.log("in test");
  a.testfromb();
});

在a.js模块中,atest()方法供b模块调用,testfromb()方法则调用b模块的方法。


define(function(require){
  var b = require("js/b");
  console.log("in a");
  return {
    atest:function(){
      console.log("test in a");
    },
    testfromb:function(){
      console.log("testfromb in a");
      b.btest();
    }
  }
});

b模块中调用了a模块的方法。


define(function(require){
  var a = require("js/a");
  console.log("in b");
  return {
    btest:function(){
      console.log("test in b");
      a.atest();
    }
  }
});

这种相互调用导致a依赖b,而b又依赖a,形成循环依赖。浏览器控制台会抛出如下错误:

Uncaught Error: Module name "js/a" has not been loaded yet for context: _

官方文档指出,循环依赖属于设计缺陷,应尽量避免。若无法避免,可通过修改b模块来解决:


define(function(require){
  // var a = require("js/a");
  console.log("in b");
  return {
    btest:function(){
      console.log("test in b");
      require("js/a").atest();
    }
  }
});

此处改为在调用atest()方法时才动态加载a模块,此时a模块必然已完成加载。查看输出信息可见:


in b
a.js:3 in a
test.js:6 in test
a.js:9 testfromb in a
b.js:6 test in b
a.js:6 test in a

RequireJS与jQuery模块化开发背景

采用相同方式修改a模块可能无效,因为模块加载顺序是从b开始的。

关于循环依赖的完整源码可参考提供的云盘链接。

RequireJS中集成jQuery及插件

如何在requirejs中使用jquery

若要在RequireJS中使用jQuery,只需在main.js中添加相应依赖即可:


requirejs.config({
  baseUrl: './',
  paths:{
    'jquery':'lib/jquery'
  }
});

requirejs(['jquery'],
function ($){
  $('#test').html('test');
});

如何在requirejs中使用jquery插件

对于jquery的插件,比较常见的做法都是传入一个jquery的对象,在这个jquery对象的基础上添加插件对应的方法。

首先需要添加jquery插件的依赖,这里用两个插件举例子——jquery-ui和jquery-datatables

requirejs.config({
  baseUrl: './',
  paths:{
    'jquery':'lib/jquery',
    'jquery-ui':'lib/jquery-ui',
    'jquery-dataTables':'lib/jquery.dataTables'
  },
  shim:{
    'jquery-ui':['jquery'],
    'jquery-dataTables':['jquery']
  }
});

requirejs(['jquery','jquery-ui','jquery-dataTables'],
function ($){
  ....
});

由于jquery插件都需要依赖于jquery,因此可以在shim中指定依赖关系。
除了上面这种使用方法,也可以使用commonJS风格的调用:


define(function(require){
  var $ = require('jquery');
  require('jquery-ui');
  require('jquery-dataTables');
  
    //下面都是测试,可以忽略
  var _test = $('#test');
  _test.selectmenu({
    width : 180,
    change : function(event, ui) {
      console.log('change');
    }
  });
  return {
    test:function(){
      //测试jquery-ui
      _test.append($('<option>test1</option><option>test1</option>'));
      _test.selectmenu("refresh");
      //测试jquery-datatables
      var _table = $('table');
      _table.dataTable();
    }
  }
});

然而,执行上述代码会抛出异常:

Uncaught TypeError: _table.dataTable is not a function

这是因为DataTables并非遵循RequireJS规范的模块,直接引入不会执行其内部的匿名函数。需修改其匿名函数,传入jQuery对象,并在最后一行添加:


*/

  return $.fn.dataTable;
//}));原来是这样
}($)));//这里增加执行这个匿名函数,并且传入$对象。

}(window, document));

这是网络上常见的解决方法,但由于经验不足,对其原理理解尚浅。

样例代码可参考云盘。由于引入的资源不全,可能会报错,可直接忽略,只要能执行UI插件即表示集成成功。

jQuery UI插件与DOM事件处理

requirejs使用jquery-ui的问题

由于RequireJS加载JS文件后会立即执行,若jQuery UI插件需要刷新DOM页面,可能导致页面事件失效。

例如,模块加载后对元素$('#test')绑定了click事件。若使用某UI插件重新渲染DOM,test对应的click事件将失效。

解决办法:

• 将事件绑定推迟到DOM元素渲染完成后手动触发; • 或使用事件捕获代替DOM元素的事件绑定(操作繁琐,不推荐)。

例如在DOM重构的JS模块中,执行渲染代码后:

require("xxx").initEvents(); 常见场景:

如在页面中使用jquery-steps UI插件,它会重新渲染页面,导致最初绑定的事件失效。必须推迟到JS重构页面后再绑定事件。

以上这篇基于RequireJS和JQuery的模块化编程——常见问题全面解析就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章