RequireJS实例教程及命名冲突解决

来源:互联网 发布:手机任意显示软件 编辑:程序博客网 时间:2024/06/07 01:13

require.js是一个遵循AMD规范,可以实现.js文件按需分块加载的前端框架。举个例子,我们在写前端代码时,常常会看到如下的写法:

<script src="1.js"></script><script src="2.js"></script><script src="3.js"></script><script src="4.js"></script>
这段代码依次加载多个js文件,这样的写法有很大的缺点。首先,加载的时候,浏览器会停止网页渲染,加载文件越多,网页失去响应的时间就会越长;其次,由于js文件之间存在依赖关系,因此必须严格保证加载顺序(比如上例的1.js要在2.js的前面),依赖性最大的模块一定要放到最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。使用require.js框架即可彻底解决这种难题。

我们可以去官网下载require.js,使用该框架,在我们的html页面中常常如下引入:

<script src="js/libs/require.js" defer async="true" data-main="js/main"></script>
async属性表明这个文件需要异步加载,避免网页失去响应。IE不支持这个属性,只支持defer,所以把defer也写上。data-main则表示我们自己的代码主文件所在路径。在上例中,就是js目录下面的main.js,这个文件会第一个被require.js加载。由于require.js默认的文件后缀名是js,所以可以把main.js简写成main。

main.js作为require.js第一个引入的js文件,自然要遵循一定的写法规范。首先,require.js主要目的是支持js按需分块加载,所以第一步是把相关的js文件按模块引入,写法如下:

//模块的配置requirejs.config({baseUrl: "./",paths: {"jquery": "js/libs/jquery-1.8.0","common": "js/libs/common","countObject": "js/core/countObject","dependCount": "js/core/dependCount","countFunction": "js/core/countFunction"}});
其中,baseUrl表示main.js目录的相对目录,依据相对目录规则可知"./"表示当前引入文件基目录与main.js在同一目录层级下;paths表示各个引入js文件在以baseUrl为基目录的基础上的详细目录地址。已jquery为例:jquery的引用目录是"./js/libs/jquery-1.8.0"。

当前Demo的目录结构如图所示:

(注)此步requirejs.config引用模块中,虽指出了各个js所在路径,但实际上并没有加载进来,实际加载进来是在接下来的模块引用代码中生效。

在上一步中js文件的引用配置已经配好了,接下来就是对所需的模块进行加载。模块加载的代码如下:

//应用程序requirejs(['_main_']);define("_main_", ["jquery", "common", "countObject", "countFunction", "dependCount"], function($, common, countObject, countFunction, dependCount) {//your code});
模块使用define()函数来定义,上面代码中define("_main_",.......)表示将main.js定义为名称是"_main_"的模块,requirejs(['_main_']);则表示引用该模块。这种定义模块名称的写法常常用在1对1的关系中,即1个html文件相对应1个主js文件,如demo中的index.html中的data-main="js/main"相对应的1个js文件是main.js。其他自定义模块引用如后面将介绍到的countObject.js,定义时无需定义模块名称,用define(function() {});即可。

define(...,[?],....)中[?]是一个字符串数组,字符串值为requirejs.config配置中paths的属性值,根据实际需要引入main.js中所需的模块,define(...,...,function(?,?,?){});中的function(?,?,?){}表示这些模块的外部调用名称,正常情况下与引入模块名称一致。

解决了模块的引用和加载,接下来就是这些模块的在代码中如何使用了。如对jquery模块的引用,由于该模块定义的外部名称是$,所以在使用时按照jquery的习惯使用$即可调用,其他模块调用大致相同,如countObject.add(1,1),表示送出1加1的结果。接下来主要讲讲countObject、countFunction和dependCount这三种常用的自定义模块的写法。

第一种是没有依赖于任何其他模块的自定义模块,如本Demo中的countObject

//非依赖对象定义define(function() {var module = {};module.value = 0;//加法var add = function(a, b) {return a + b;}//减法var minus = function(a, b) {return a - b;}module.add = add;module.minus = minus;return module;});
第二种是有依赖于其他模块的自定义模块,如dependCount:
//依赖对象定义define(['./countObject'], function(countObject) {var module = {};//加法var add = countObject.add;//减法var minus = countObject.minus;module.add = add;module.minus = minus;return module;});
这两种模块的使用方法都是通过“.“的来引用,如countObject.add(1,1)。

还有一种写法是用过new Object()的方法来引用,这类模块的写法如下:

define(function() {var target = null;function countTool() {target = this;target.value = 0;};countTool.prototype.add = function(a, b) {return a + b;};countTool.prototype.minus = function(a, b) {return a - b;};return countTool;});
使用方法是:
var c = new countFunction();var r = c.add(1,1);console.log(r); // 2
理论上,require.js加载的模块,必须是按照AMD规范、用define()函数定义的模块。但是实际上,虽然已经有一部分流行的函数库(比如jQuery)符合AMD规范,更多的库并不符合。那么,require.js是否能够加载非规范的模块呢?回答是可以的,在配置项时使用shim即可。不符合AMD规范的第三方库常见的有两种写法:第一种写法是

//dateUtil.js(function(window) {var DateUtils = {};DateUtils.toString = function() {alert("toString");};// 全局变量window.DateUtils = DateUtils;})(window);
另一种写法是:

//stringUtil.jsvar StringUtils = {};StringUtils.toUpperCase = function(input) {alert("toUpperCase");}
要引用这两种脚本,可以使用如下代码:

//模块的配置requirejs.config({baseUrl: "./",paths: {"jquery": "js/libs/jquery-1.8.0","common": "js/libs/common","countObject": "js/core/countObject","dependCount": "js/core/dependCount","countFunction": "js/core/countFunction","dateUtil": "js/core/dateUtil","stringUtil": "js/core/stringUtil"},shim: {dateUtil: {deps: [],exports: 'DateUtils'},stringUtil: {deps: [],exports: 'StringUtils'}}});//应用程序requirejs(['_main_']);define("_main_", ["jquery", "common", "countObject", "countFunction", "dependCount", "dateUtil", "stringUtil"], function($, common, countObject, countFunction, dependCount, dateUtil, stringUtil) {//your codestringUtil.toUpperCase();dateUtil.toString();window.StringUtils.toUpperCase();window.DateUtils.toString();});
shim中deps表示该js的依赖项,如依赖于jquery,则为deps: [jquery],没有依赖则为空数组。第二个参数exports表示该js对外应用时的名称,即js中的对外应用的全局变量,如dateUtil.js中的DateUtils。
在实际应用中,还有一类第三方库的情况,它自身也定义了一个require,如下图所示psd.js库


这样的库必然会与require.js中的require相冲突,这时想要在require.js框架中使用这类自带require函数的第三方库,怎么办呢?首先,可以在使用psd.js库前,把已有的require.js框架全局变量保存下来,然后将psd.js动态加载进来,使用完成后,在对require.js框架全局变量进行重置。

//使用前var _define = null;var _requirejs = null;var _require = null;_define = window.define;_requirejs = window.requirejs;_require = window.require;window.requirejs = null;window.require = null;window.define = null;//加载psd.jsloadFiles([url + '/psd.js'], function() {//使用psd.js//some code//使用后window.define = _define;window.requirejs = _requirejs;window.require = _require;});// 动态加载js文件function loadFiles(urlArrValue, callback) {var staticPath = "";var urlArr = urlArrValue;var filesNum = urlArr.length;var loadedCount = 0;if(filesNum > 0) {var url = staticPath + urlArr[loadedCount];Load(url);}function Load(url) {var f;if(url.indexOf(".css") > 0) {f = document.createElement("link");f.type = 'text/css';f.rel = "stylesheet";f.href = url;} else {f = document.createElement("script");f.type = "text/javascript";f.src = url;}f.onload = function(e) {loadedCount++;if(loadedCount < filesNum) {var url = staticPath + urlArr[loadedCount];Load(url);} else {callback();}}f.onerror = function(e) {loadedCount++;if(loadedCount < filesNum) {var url = staticPath + urlArr[loadedCount];Load(url);} else {callback();}}document.head.appendChild(f);}}

实例Demo下载地址:http://download.csdn.net/detail/zeping891103/9885475