基于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对象、属性、事件手册集合方便查询
Jul 04 Javascript
一些常用弹出窗口/拖放/异步文件上传等实用代码
Jan 06 Javascript
深入Javascript函数、递归与闭包(执行环境、变量对象与作用域链)使用详解
May 08 Javascript
Js放到HTML文件中的哪个位置有什么区别
Aug 21 Javascript
浅谈JavaScript的事件
Feb 27 Javascript
jQuery插件MixItUp实现动画过滤和排序
Apr 12 Javascript
js 博客内容进度插件详解
Feb 19 Javascript
Vue中android4.4不兼容问题的解决方法
Sep 04 Javascript
vue项目每30秒刷新1次接口的实现方法
Dec 04 Javascript
js纯前端实现腾讯cos文件上传功能的示例代码
May 14 Javascript
Vue开发中遇到的跨域问题及解决方法
Feb 11 Javascript
JavaScript ES6的函数拓展
Jan 18 Javascript
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
php中计算未知长度的字符串哪个字符出现的次数最多的代码
2012/08/14 PHP
PHP实现的字符串匹配算法示例【sunday算法】
2017/12/19 PHP
php实现数组重复数字统计实例
2018/09/30 PHP
js获取url中指定参数值的示例代码
2013/12/14 Javascript
Javascript高级技巧分享
2014/02/25 Javascript
原生js实现移动开发轮播图、相册滑动特效
2015/04/17 Javascript
利用jQuery来动态为属性添加或者删除属性的简单方法
2016/12/02 Javascript
easyUI combobox实现联动效果
2017/01/17 Javascript
JS前端开发判断是否是手机端并跳转操作(小结)
2017/02/05 Javascript
编写React组件项目实践分析
2018/03/04 Javascript
jQuery事件blur()方法的使用实例讲解
2019/03/30 jQuery
通过jQuery学习js类型判断的技巧
2019/05/27 jQuery
JavaScript判断对象和数组的两种方法
2019/05/31 Javascript
js类的继承定义与用法分析
2019/06/21 Javascript
Vue + Element UI图片上传控件使用详解
2019/08/20 Javascript
Vue.js实现大转盘抽奖总结及实现思路
2019/10/09 Javascript
jQuery+PHP+Ajax实现动态数字统计展示功能
2019/12/25 jQuery
VSCode搭建React Native环境
2020/05/07 Javascript
[06:16]《DAC最前线》之地区预选赛全面回顾
2015/01/19 DOTA
在Django中使用Sitemap的方法讲解
2015/07/22 Python
Python语言描述最大连续子序列和
2017/12/05 Python
python如何读写csv数据
2018/03/21 Python
python 寻找list中最大元素对应的索引方法
2018/06/28 Python
python文件操作的简单方法总结
2019/11/07 Python
python opencv圆、椭圆与任意多边形的绘制实例详解
2020/02/06 Python
html5 Canvas画图教程(6)—canvas里画曲线之arcTo方法
2013/01/09 HTML / CSS
html5中audio支持音频格式的解决方法
2018/08/24 HTML / CSS
美国家居用品和厨具购物网站:DealsDot
2019/10/07 全球购物
同步和异步有何异同,在什么情况下分别使用他们?举例说明
2014/02/27 面试题
有个性的自我评价范文
2013/11/15 职场文书
专业销售业务员求职信
2013/11/18 职场文书
大学毕业生的自我鉴定
2013/11/30 职场文书
街道党工委党的群众路线教育实践活动对照检查材料思想汇报
2014/10/05 职场文书
同学聚会致辞集锦
2015/07/28 职场文书
python多次执行绘制条形图
2022/04/20 Python
git中cherry-pick命令的使用教程
2022/06/25 Servers