基于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 相关文章推荐
两个DIV等高的JS的实现代码
Dec 23 Javascript
基于jQuery判断两个元素是否有重叠部分的代码
Jul 25 Javascript
JavaScript快速检测浏览器对CSS3特性的支持情况
Sep 26 Javascript
jQuery+css实现图片滚动效果(附源码)
Mar 18 Javascript
JavaScript中对循环语句的优化技巧深入探讨
Jun 06 Javascript
jQuery异步上传文件插件ajaxFileUpload详细介绍
May 19 Javascript
利用jQuery的动画函数animate实现豌豆发射效果
Aug 28 Javascript
JS中利用localStorage防止页面动态添加数据刷新后数据丢失
Mar 10 Javascript
vue 2.0封装model组件的方法
Aug 03 Javascript
jquery-file-upload 文件上传带进度条效果
Nov 21 jQuery
jquery实现的简单轮播图功能【适合新手】
Aug 17 jQuery
微信小程序wx.request的简单封装
Nov 13 Javascript
[原创]JQuery 在表单提交之前修改 提交的值
Apr 14 #Javascript
javaScript数组迭代方法详解
Apr 14 #Javascript
基于JS实现移动端访问PC端页面时跳转到对应的移动端网页
Dec 24 #Javascript
js贪吃蛇游戏实现思路和源码
Apr 14 #Javascript
JS跨域解决方案之使用CORS实现跨域
Apr 14 #Javascript
[原创]Bootstrap 中下拉菜单修改成鼠标悬停直接显示
Apr 14 #Javascript
Seajs 简易文档 提供简单、极致的模块化开发体验
Apr 13 #Javascript
You might like
德劲1103二次变频版的打磨
2021/03/02 无线电
Yii PHP Framework实用入门教程(详细介绍)
2013/06/18 PHP
php操作MongoDB类实例
2015/06/17 PHP
php文件上传类完整实例
2016/05/14 PHP
php接口技术实例详解
2016/12/07 PHP
laravel实现一个上传图片的接口,并建立软链接,访问图片的方法
2019/10/12 PHP
php 中的信号处理操作实例详解
2020/03/04 PHP
jQuery fadeTo方法调整图片的透明度使用介绍
2013/05/06 Javascript
Javascript基础知识(一)核心基础语法与事件模型
2014/09/29 Javascript
angularjs中的单元测试实例
2014/12/06 Javascript
js的for in循环和java里foreach循环的区别分析
2015/01/28 Javascript
Angular 根据 service 的状态更新 directive
2016/04/03 Javascript
jQuery移动端日期(datedropper)和时间(timedropper)选择器附源码下载
2016/04/19 Javascript
vue微信分享 vue实现当前页面分享其他页面
2017/12/02 Javascript
浅谈JsonObject中的key-value数据解析排序问题
2017/12/06 Javascript
Vue精简版风格指南(推荐)
2018/01/30 Javascript
vue.js使用watch监听路由变化的方法
2018/07/08 Javascript
Vue通过配置WebSocket并实现群聊功能
2019/12/31 Javascript
js实现简单选项卡制作
2020/08/05 Javascript
Node.js 中判断一个文件是否存在
2020/08/24 Javascript
详解Java中String JSONObject JSONArray List转换
2020/11/13 Javascript
vue表单验证之禁止input输入框输入空格
2020/12/03 Vue.js
Python简单实现enum功能的方法
2016/04/25 Python
Python中Numpy mat的使用详解
2019/05/24 Python
Python爬虫基于lxml解决数据编码乱码问题
2020/07/31 Python
CSS3 三维变形实现立体方块特效源码
2016/12/15 HTML / CSS
IE9对HTML5中部分属性不支持的原因分析
2014/10/15 HTML / CSS
英国计算机产品零售商:Novatech(定制个人电脑、笔记本电脑、工作站和服务器)
2018/01/28 全球购物
实习自我鉴定模板
2013/09/28 职场文书
研发工程师的岗位职责
2013/11/18 职场文书
银行存款证明样本
2014/01/17 职场文书
元旦晚会邀请函
2014/02/01 职场文书
个人公开承诺书
2014/03/28 职场文书
装饰公司活动策划方案
2014/08/23 职场文书
党支部组织生活会整改方案
2014/09/30 职场文书
Python数据可视化之用Matplotlib绘制常用图形
2021/06/03 Python