js模块化开发
一、什么是模块化?
模块化是指解决一个复杂的问题时自顶向下把系统划分成若干模块的过程,有多种属性,分别反映其内部特性。
二、为什么要模块化(模块化的好处)?
1.更好地分离
如果要加载多个就得就得放置多个script标签,如果是加载模块的话,如seaJS,就只需加载一个sea.js即可,这样对于HTML和JavaScript分离很有好处。
2.更好的代码组织方式
如果单个文件越来越大,维护起来问题出问题的几率也会越来越大,一个人开发还好,如果是多人开发,不同的代码风格,超多的业务逻辑混杂在一起,不要说维护了,光想想就蛋疼。模块化的开发,一个文件就是一个模块,控制了文件的粒度,每个模块可以专注于一个功能,在多人开发时,各自管好自己的模块就行。
3.按需加载
还是以单个文件来说,当文件大到一定程度,性能问题也随之而来。合并文件是能减少请求,性能也会有所提升,但是当文件大到一定的体积时,此时的下载时间可能并不会比多个小文件的下载时间短,此时就需要权衡请求数和文件体积的关系了。
4.避免命名冲突
JavaScript本身是没有命名空间的,为了避免命名冲突,经常会使用对象或闭包的办法来避免。用对象仅仅是降低了冲突的概率而已,那经常使用的jQuery开发来说,无论是往$上扩张还是在$.fn上扩展,开发的人多了难免会起冲突。或者用自定义对象,搞个好几层,不光是写起来难记,这样的调用也会在性能上打折扣的。模块化就能很好的解决这个问题,在该模块内的任何形式的命名都不会再和其他模块有冲突。
5.更好的依赖处理
传统的开发模式,如果B文件要依赖A文件,那么必须在B文件前面用script标签先加载好A文件。如果有一天,B文件不再需要依赖A文件,或者需要增加依赖文件C,那么又得在B文件前面用script标签加载C文件。如果这个B文件被N个页面在调用,而且页面还跨业务站点,那么改起来简直就是噩梦。如果是使用模块化,只需要在模块内部申明好依赖的就行,增加删除都直接修改模块即可,在调用的时候也不用管该模块依赖了哪些其他模块。
三、模块化规范
1.commonJS:通用的模块规范(同步);
2.AMD:异步模块定义规范(预加载);
3.CMD:通用模块定义规范(延迟加载)。
四、模块化框架
1.requireJS(支持AMD规范的模块化框架)
实例:
**主页面:** <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>requireJS测试</title> <link rel="stylesheet" href="./css/bootstrap.min.css" /> <script src="./js/require.js" data-main="./js/main"></script> </head> <body> <h1>首页</h1> <div> <input type="button" value="显示所有"/> <input type="button" value="增加"/> <input type="button" value="修改"/> <input type="button" value="删除"/> </div> <div class="modal fade" id="myModal"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <h4 class="modal-title">Modal title</h4> </div> <div class="modal-body"> <p>One fine body…</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> <button type="button" class="btn btn-primary">Save changes</button> </div> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div><!-- /.modal --> </body> </html> data-main属性的作用是,指定网页程序的主模块。在上例中,就是js目录下面的main.js,这个文件会第一个被require.js加载。由于require.js默认的文件后缀名是js,所以可以把main.js简写成main。 **编写主配置文件:** //主入口配置 require.config({ paths:{ student:"./student", jquery:"./jquery-1.9.1.min", bootsrap:"./bootstrap.min" } }); //主入口方法(预加载student模块和jQuery模块) require(["student","jquery"],function(stu,$){ console.log($("h1").html()); $("input:button:eq(0)").click(stu.showAll); $("input:button:eq(1)").click(stu.add); $("input:button:eq(2)").click(stu.update); $("input:button:eq(3)").click(stu.del); }); **编写student模块:** define(["jquery","bootstrap"],function($){ console.log("加载student模块"); $("#myModal").modal(); function showAll(){ console.log("执行showAll"); } function add(){ console.log("执行add"); } function update(){ console.log("执行update"); } function del(){ console.log("执行del"); } //暴露student模块里的函数 return{ "showAll":showAll, "add":add, "update":update, "del":del } });
2.seaJS(支持CMD规范的模块化框架)
实例:
**主页面:** <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>首页</title> <link rel="stylesheet" href="./css/bootstrap.min.css" /> <script src="js/sea.js"></script> </head> <body> <h1>首页</h1> <div> <input type="button" value="显示所有"/> <input type="button" value="增加"/> <input type="button" value="修改"/> <input type="button" value="删除"/> </div> <div class="modal fade" id="myModal"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <h4 class="modal-title">Modal title</h4> </div> <div class="modal-body"> <p>One fine body…</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> <button type="button" class="btn btn-primary">Save changes</button> </div> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div><!-- /.modal --> </body> <script> //seaJS配置 seajs.config({ base:"../seaJS", alias:{ main:"js/main", student:"js/student", jquery:"js/jquery-1.9.1.min", bootstrap:"js/bootstrap.min" } }); //加载主模块 seajs.use("main"); </script> </html> **编写main模块:** define(function(require,exports,module){ var stu = require("student"); stu.showAll(); stu.add(); stu.update(); stu.del(); var $ = require("jquery"); $("input:button:eq(0)").click(stu.showAll); console.log($("h1")); }); **编写student模块:** define(function(require,exports,module){ console.log("加载student模块"); var $ = require("jquery"); require("bootstrap")($); function showAll(){ console.log("执行showAll"); $("#myModal").modal(); } function add(){ console.log("执行add"); } function update(){ console.log("执行update"); } function del(){ console.log("执行del"); } //暴露student模块中的函数,方法一 // exports.showAll = showAll; // exports.add = add; // exports.update = update; // exports.del = del; //暴露student模块中的函数,方法二 module.exports = { "showAll":showAll, "add":add, "update":update, "del":del }; //暴露student模块中的函数,方法三 // return { // "showAll":showAll, // "add":add, // "update":update, // "del":del // } });
注意:seaJS导入第三方js模块是需要修改第三方JS的源码,例如:
seaJS加载jQuery模块,需要修改jQuery.js原有代码,修改如下:
define(function(){
jQuery.js原有代码
return $.noConflict();
});
seaJS加载boostrap模块,同样需要修改boostrap.js原有代码,修改如下:
define(function(){
return function($){
boostrap.js原有代码
}
});