基于RequireJS和JQuery的模块化编程——常见问题全面解析


Posted in Javascript onApril 14, 2016

由于js的代码逻辑越来越重,一个js文件可能会有上千行,十分不利于开发与维护。最近正在把逻辑很重的js拆分成模块,在一顿纠结是使用requirejs还是seajs的时候,最终还是偏向于requirejs。毕竟官方文档比较专业嘛...

不过即便是有完整的官方文档,仍然遇到不少的问题,比如jquery-ui的使用。

下面就循序渐进的讲解一下我遇到的问题,以及解决的办法。

关于AMD和CMD的理解

AMD(异步模块定义)的典型就是requirejs,而CMD(通用模块定义)的典型是淘宝的seajs。

他们的相同点是,都会异步的加载js。但是不同点是,require.js加载完会立即执行;而seajs则是等到进入主函数需要执行时才执行。

如果使用seajs初始的加载执行效率会比较高,但是在使用的过程中可能会取执行js,因此可能会出现卡顿,影响用户体验(由于我也没试过,要是说错了,别见怪)。而requirejs则是在一开始就把所有加载的js都执行,这时,如果你的模块中有一些执行方法,它们可能并不会按照你想的顺序执行。

因此,如果已经习惯了异步编程,并且希望有完善的文档推荐使用requirejs;如果是想对执行顺序有特殊要求,又方便开发,那么也可以使用seajs。

如何解决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

如果想要使用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并不是一个require风格的模块,因此直接这样引入,并不会执行它内部的匿名函数。可以修改它的匿名函数,传入$对象,在最后一行:

*/

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

}(window, document));

这也是在网上搜的方法,原理奈何经验不足....

样例代码可以参考云盘,由于引入的资源不是很全,所以会报错,可以直接忽略,因为能执行UI插件就表示已经成功了。

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的模块化编程——常见问题全面解析就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript前补零操作实例
Mar 11 Javascript
javascript获取当前的时间戳的方法汇总
Jul 26 Javascript
开源免费天气预报接口API及全国所有地区代码(国家气象局提供)
Dec 26 Javascript
Vue.js实战之通过监听滚动事件实现动态锚点
Apr 04 Javascript
jQuery插件artDialog.js使用与关闭方法示例
Oct 09 jQuery
vue-cli中打包图片路径错误的解决方法
Oct 26 Javascript
Vue.js轮播图走马灯代码实例(全)
May 08 Javascript
微信小程序日历弹窗选择器代码实例
May 09 Javascript
vue使用prop可以渲染但是打印台报错的解决方式
Nov 13 Javascript
Nuxt pages下不同的页面对应layout下的页面布局操作
Nov 05 Javascript
如何用Node.js编写内存效率高的应用程序
Apr 30 Javascript
vue实现水波涟漪效果的点击反馈指令
May 31 Vue.js
Jquery实现$.fn.extend和$.extend函数
Apr 14 #Javascript
详解Jquery实现ready和bind事件
Apr 14 #Javascript
一起学写js Calender日历控件
Apr 14 #Javascript
jQuery获取父元素节点、子元素节点及兄弟元素节点的方法
Apr 14 #Javascript
原生js实现autocomplete插件
Apr 14 #Javascript
jQuery循环遍历子节点并获取值的方法
Apr 14 #Javascript
基于jQuery实现音乐播放试听列表
Apr 14 #Javascript
You might like
ThinkPHP调用百度翻译类实现在线翻译
2014/06/26 PHP
Codeigniter发送邮件的方法
2015/03/19 PHP
php判断手机浏览还是web浏览,并执行相应的动作简单实例
2016/07/28 PHP
XHTML-Strict 内允许出现的标签
2006/12/11 Javascript
一个简单的网站访问JS计数器 刷新1次加1次访问
2012/09/20 Javascript
让低版本浏览器支持input的placeholder属性(js方法)
2013/04/03 Javascript
html文件中jquery与velocity变量中的$冲突的解决方法
2013/11/01 Javascript
基于javascript滚动图片具体实现
2013/11/18 Javascript
JS获取屏幕,浏览器窗口大小,网页高度宽度(实现代码)
2013/12/17 Javascript
jquery uploadify 在FF下无效的解决办法
2014/09/26 Javascript
jQuery中:disabled选择器用法实例
2015/01/04 Javascript
JavaScript程序中实现继承特性的方式总结
2016/06/24 Javascript
jquery根据td给相同tr下其他td赋值的实现方法
2016/10/05 Javascript
Vue源码探究之状态初始化
2018/11/14 Javascript
使用easyui从servlet传递json数据到前端页面的两种方法
2019/09/05 Javascript
Vue自动构建发布脚本的方法示例
2020/07/24 Javascript
[01:01:52]完美世界DOTA2联赛PWL S2 GXR vs Magma 第二场 11.25
2020/11/26 DOTA
[01:02:26]DOTA2-DPC中国联赛 正赛 SAG vs RNG BO3 第二场 1月18日
2021/03/11 DOTA
python函数缺省值与引用学习笔记分享
2013/02/10 Python
详解在Python程序中解析并修改XML内容的方法
2015/11/16 Python
基于Python实现对PDF文件的OCR识别
2016/08/05 Python
详谈Python高阶函数与函数装饰器(推荐)
2017/09/30 Python
Python编程scoketServer实现多线程同步实例代码
2018/01/29 Python
python多线程并发实例及其优化
2019/06/27 Python
Python numpy线性代数用法实例解析
2019/11/15 Python
浅谈Pytorch中的自动求导函数backward()所需参数的含义
2020/02/29 Python
Pytorch通过保存为ONNX模型转TensorRT5的实现
2020/05/25 Python
铭万公司.net面试题笔试题
2014/07/20 面试题
Java程序员面试题
2016/09/27 面试题
捐款倡议书
2014/04/14 职场文书
反四风对照检查材料思想汇报
2014/09/16 职场文书
县级领导干部开展党的群众路线教育实践活动工作汇报
2014/10/25 职场文书
中小学生学籍证明
2014/10/25 职场文书
PostgreSQL解析URL的方法
2021/08/02 PostgreSQL
Python requests用法和django后台处理详解
2022/03/19 Python
2022年显卡天梯图(6月更新)
2022/06/17 数码科技