require.js是一个js库,相关的基础知识,前面转载了两篇博文:javascript模块化编程(require.js),Javascript模块化工具require.js教程,RequireJS 参考文章
1. require.js的主要作用是js的工程化,规范化:
1)它是一个js脚本的加载器,它遵循AMD(Asynchronous Module Definition)规范,实现js脚本的异步加载,不阻塞页面的渲染和其后的脚本的执行。
并提供了在加载完成之后的执行相应回调函数的功能;
2)它要求js脚本的模块化,也就是文件化;require.js的作用之一就是加载js模块,也就是js文件。所以我们的js的书写应该模块化,也就是文件化。
3)它可以管理js模块/文件之间的依赖; js模块化,文件化之后,它们之间的依赖可以通过require.js优雅的解决;
4)require.js中提供的优化器 r.js 可以来优化页面中的js脚本和CSS文件,达到提高页面响应速度,减少页面所需要的http/https请求次数。在极端优化的情况下,通过r.js优化之后的页面只需要一次js脚本请求和一次CSS文件请求。这就极大的减少了页面所需要的http/https请求的次数,提高了页面的加载速度。r.js的优化分为两种方式:一是压缩js和css文件,也就是去掉空格,空行,将长变量名换成短变量名之类的;二是合并多个js文件为一个js文件,合并多个css文件为一个。
5) 通过使用require.js之后,我们只需要在页面引入一行<script>标签,类似于:<script src="js/require.js" data-main="js/login.js"></script>,甚至也可以只引入一行<style>标签,十分优雅。注意引入一行<script>标签并不等价于只需要一次js的http/https的请求。
2. require.js模块的写法:
require.js要求我们的js模块,也就是js文件按照一定的格式书写:也就是最好通过define()函数来写js模块,比如:math.js
define(function(){var add = function(x,y){return x+y;};return{add:add};});
math.js通过define()函数,定义了一个符合require.js要求的js模块,它的返回值是一个对象,有一个属性add,它是一个函数。通过下的方式就可以来调用该js模块中定义的函数:
require.config({baseUrl:"/ems/js/",paths:{"math":"math"}});require(["math"], function(math){alert(math.add(100,20));});
require.config的主要作用是配置 模块ID/模块名称 和 它对应的js文件所在的位置。上面的那个配置就是将 /ems/js/math.js(ems是项目名称) 文件配置成一个ID为math的模块,然后通过 require(["math"], function(math)(){}); 就可以异步来加载 /ems/js/math.js 文件,加载完成之后,执行回调函数。回调函数中调用了math模块中的add方法。
在看一个例子:
/** * This jQuery plugin displays pagination links inside the selected elements. * * @author Gabriel Birke (birke *at* d-scribe *dot* de) * @version 1.2 * @param {int} maxentries Number of entries to paginate * @param {Object} opts Several options (see README for documentation) * @return {Object} jQuery Object */define(['jquery'], function($){jQuery.fn.pagination = function(maxentries, opts){opts = jQuery.extend({items_per_page:10,num_display_entries:10,current_page:0,num_edge_entries:0,link_to:"#",PRev_text:"Prev",next_text:"Next",ellipse_text:"...",prev_show_always:true,next_show_always:true,callback:function(){return false;}},opts||{});return this.each(function() {function numPages() {return Math.ceil(maxentries/opts.items_per_page);}function getInterval() {var ne_half = Math.ceil(opts.num_display_entries/2);var np = numPages();var upper_limit = np-opts.num_display_entries;var start = current_page>ne_half?Math.max(Math.min(current_page-ne_half, upper_limit), 0):0;var end = current_page>ne_half?Math.min(current_page+ne_half, np):Math.min(opts.num_display_entries, np);return [start,end];}function pageSelected(page_id, evt){current_page = page_id;drawLinks();var continuePropagation = opts.callback(page_id, panel);if (!continuePropagation) {if (evt.stopPropagation) {evt.stopPropagation();}else {evt.cancelBubble = true;}}return continuePropagation;}function drawLinks() {panel.empty();var interval = getInterval();var np = numPages();var getClickHandler = function(page_id) {return function(evt){ return pageSelected(page_id,evt); };}var appendItem = function(page_id, appendopts){page_id = page_id<0?0:(page_id<np?page_id:np-1);appendopts = jQuery.extend({text:page_id+1, classes:""}, appendopts||{});if(page_id == current_page){var lnk = jQuery("<span class='current'>"+(appendopts.text)+"</span>");}else{var lnk = jQuery("<a>"+(appendopts.text)+"</a>").bind("click", getClickHandler(page_id)).attr('href', opts.link_to.replace(/__id__/,page_id));}if(appendopts.classes){lnk.addClass(appendopts.classes);}panel.append(lnk);}if(opts.prev_text && (current_page > 0 || opts.prev_show_always)){appendItem(current_page-1,{text:opts.prev_text, classes:"prev"});}if (interval[0] > 0 && opts.num_edge_entries > 0){var end = Math.min(opts.num_edge_entries, interval[0]);for(var i=0; i<end; i++) {appendItem(i);}if(opts.num_edge_entries < interval[0] && opts.ellipse_text){jQuery("<span>"+opts.ellipse_text+"</span>").appendTo(panel);}}for(var i=interval[0]; i<interval[1]; i++) {appendItem(i);}if (interval[1] < np && opts.num_edge_entries > 0){if(np-opts.num_edge_entries > interval[1]&& opts.ellipse_text){jQuery("<span>"+opts.ellipse_text+"</span>").appendTo(panel);}var begin = Math.max(np-opts.num_edge_entries, interval[1]);for(var i=begin; i<np; i++) {appendItem(i);}}if(opts.next_text && (current_page < np-1 || opts.next_show_always)){appendItem(current_page+1,{text:opts.next_text, classes:"next"});}}var current_page = opts.current_page;maxentries = (!maxentries || maxentries < 0)?1:maxentries;opts.items_per_page = (!opts.items_per_page || opts.items_per_page < 0)?1:opts.items_per_page;var panel = jQuery(this);this.selectPage = function(page_id){ pageSelected(page_id);}this.prevPage = function(){ if (current_page > 0) {pageSelected(current_page - 1);return true;}else {return false;}}this.nextPage = function(){ if(current_page < numPages()-1) {pageSelected(current_page+1);return true;}else {return false;}};drawLinks(); opts.callback(current_page, this);});};return jQuery.fn.pagination;});
上面的define()函数定义了一个jquery的分页插件(文件名:jquery.pagination.js),它符合require.js模块的规范。define(['jquery'], function($)... 表示该模块依赖于 jquery 模块,并向回调函数传入jquery的全局对象 $, 那么这里的 ['jquery'] 又来自哪里呢?它其实来自于:
require.config({ baseUrl:"/ems/js/",paths: {"jquery": "jquery.min"}});
该配置将 /ems/js/jquery.min.js 配置成require.js的模块,模块ID为"jquery",所以我们才能使用 define(['jquery'], function($) 来引用"jquery"模块。
define(["xxx","yyy"], function(xxx,yyy){}); define函数定义符合require.js规范的模块,数组参数指定该模块依赖的所有模块,那么这些被依赖的模块异步加载完成之后,然后执行回调函数,回调函数的返回值就是该模块的定义。返回值一般是一个对象,或者一个函数。然后该模块又可以被其它模块所依赖和使用。比如上面的: jquery.pagination.js,它定义了一个jquery的分页插件,那么通过下面的配置,我就可以使用它:
require.config({baseUrl:"/ems/js/",paths: {"jquery": "jquery.min","pagination": "jquery.pagination"}});require(["pagination"], function(pagination){ $.patination(20);// ....});
再看一个例子(文件名:dateUtil.js):
define(function(){var dateFormat = function(fmt, date){if(!(date instanceof Date))return;var o = { "M+": date.getMonth() + 1, // 月份 "d+": date.getDate(), //日 "H+": date.getHours(), //24小时制 "h+" : date.getHours()%12 == 0 ? 12 : date.getHours()%12, //12小时制 "m+": date.getMinutes(), //分 "s+": date.getSeconds(), //秒 "q+": Math.floor((date.getMonth() + 3) / 3), //季度 "S": date.getMilliseconds() //毫秒 }; if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length)); for (var k in o) if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); return fmt;};return {format:dateFormat};});
通过下面的配置,就可以使用dataUtil.js中的format()函数来格式化日期对象:
require.config({baseUrl:"/ems/js/",paths: {"dateUtil": "dateUtil"}});require(["dateUtil"], function(dateUtil){ alert(dateUtil.format("yyyy-MM-dd", new Date());});
我们在页面中引入上面的文件(文件名:main.js),就可以看到执行效果:
<!DOCTYPE html><html><head></head><body> <span>body1111</span><script src="js/require.js" data-main="js/main.js"></script></body></html>
执行结果:
3. require.config函数
require.config如上面所说,主要是定义 模块ID 和 它所对应的js文件的位置。参数是一个json格式的对象,baseUrl属性指定paths中的路径的相对路径。paths是一个key/value的键值对形式,key表示模块ID,value表示相对于baseUrl的相对路径,需要省略文件后缀 .js 。还有一个shim的常用属性,用来配置不符合require.js规范的js模块(没有使用de
新闻热点
疑难解答