基于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 相关文章推荐
extjs中grid中嵌入动态combobox的应用
Jan 01 Javascript
js调用iframe实现打印页面内容的方法
Mar 04 Javascript
JS实现双击编辑可修改状态的方法
Aug 14 Javascript
jQuery实现 上升、下降、删除、添加一行代码
Mar 06 Javascript
浅谈JS获取元素的N种方法及其动静态讨论
Aug 25 Javascript
JS实现的简单标签点击切换功能示例
Sep 21 Javascript
JS实现基于拖拽改变物体大小的方法
Jan 23 Javascript
js监听html页面的上下滚动事件方法
Sep 11 Javascript
微信小程序使用map组件实现获取定位城市天气或者指定城市天气数据功能
Jan 22 Javascript
微信小程序中的video视频实现 自定义播放按钮、封面图、视频封面上文案
Jan 02 Javascript
理解JavaScript中的对象
Aug 25 Javascript
js屏蔽F12审查元素,禁止修改页面代码等实现代码
Oct 02 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
域名查询代码公布
2006/10/09 PHP
PHP 程序员的调试技术小结
2009/11/15 PHP
PHP数组 为文章加关键字连接 文章内容自动加链接
2011/12/29 PHP
教你如何快捷的使用cmd访问mysql小技巧
2014/05/26 PHP
PHP 导出Excel示例分享
2014/08/18 PHP
PHP中file_exists()判断中文文件名无效的解决方法
2014/11/12 PHP
mysql_escape_string()函数用法分析
2016/04/25 PHP
PHP大文件分割上传 PHP分片上传
2017/08/28 PHP
对于Laravel 5.5核心架构的深入理解
2018/02/22 PHP
extjs 学习笔记(一) 一些基础知识
2009/10/13 Javascript
jQuery对下拉框,单选框,多选框的操作
2014/02/21 Javascript
javascript计时器详解
2015/02/28 Javascript
JQuery的ON()方法支持的所有事件罗列
2015/02/28 Javascript
JS+CSS实现仿支付宝菜单选中效果代码
2015/09/25 Javascript
jQuery+PHP星级评分实现方法
2015/10/02 Javascript
详谈ES6中的迭代器(Iterator)和生成器(Generator)
2017/07/31 Javascript
jQuery实现DIV响应鼠标滑过由下向上展开效果示例【测试可用】
2018/04/26 jQuery
NodeJs项目中关闭ESLint的方法
2018/08/09 NodeJs
vue3.0中的双向数据绑定方法及优缺点
2019/08/01 Javascript
Layui多选只有最后一个值的解决方法
2019/09/02 Javascript
如何在selenium中使用js实现定位
2020/08/18 Javascript
[04:31]2016国际邀请赛中国区预选赛妖精采访
2016/06/27 DOTA
[01:05:30]VP vs TNC 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/20 DOTA
Python RuntimeError: thread.__init__() not called解决方法
2015/04/28 Python
django主动抛出403异常的方法详解
2019/01/04 Python
Python的条件表达式和lambda表达式实例
2019/01/31 Python
对django views中 request, response的常用操作详解
2019/07/17 Python
PyQt+socket实现远程操作服务器的方法示例
2019/08/22 Python
python2.7实现复制大量文件及文件夹资料
2019/08/31 Python
wxPython实现绘图小例子
2019/11/19 Python
如何在mac环境中用python处理protobuf
2019/12/25 Python
使用Keras画神经网络准确性图教程
2020/06/15 Python
Python使用tkinter实现摇骰子小游戏功能的代码
2020/07/02 Python
跑步、骑行和铁人三项的高性能眼镜和服装:ROKA
2018/07/06 全球购物
花店创业计划书范文
2014/02/07 职场文书
世界各国短波电台对东亚播送时间频率表(SW)
2021/06/28 无线电