Web前端知识

首页 > 免费 > Web前端知识 >

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

来源:北京汇仁智杰科技有限公司   时间:2016-04-14   点击:

  由于js的代码逻辑越来越重,一个js文件可能会有上千行,十分不利于开发与维护。最近正在把逻辑很重的js拆分成模块,在一顿纠结是使用requirejs还是seajs的时候,最终还是偏向于requirejs。下面就循序渐进的讲解一下汇仁智杰技术大师遇到的问题,以及解决的办法。
  关于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

0.png

  同样的方式,修改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));
  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重构完页面,再绑定才行。

网络营销推广 . 北京汇仁智杰科技有限公司!

地址:北京市昌平区回龙观龙冠大厦5层
咨询:13370157521
业务QQ:373002979
E - mail:sales @ huirenzhijie.com
企业网站备案:京ICP备15021091号-1

汇仁智杰与众不同

  • 有网络推广经验
  • 有网站建站队伍
  • 有大型网站建设经验
  • 致力于营销型网站建设
  • 始终坚持技术和服务同样重要
查看PC版网站
备案号:京ICP备15021091号-1 版权所有:汇仁智杰