RequireJS学习笔记(一)
RequireJs已经流行很久了,我们在项目中也打算使用它。它提供了以下功能:
1. 声明不同js文件之间的依赖
2. 可以按需、并行、延时载入js库
3. 可以让我们的代码以模块化的方式组织
在html中引入requirejs
在HTML中,添加这样的 <script>
标签:
<script src="/path/to/require.js" data-main="/path/to/app/config.js"></script>
通常我们只需要导入requirejs即可,然后指定一个入口文件,不需要显式导入其它的js库,因为这个工作会交给requirejs来做。
属性 data-main
是告诉requirejs:你下载完以后,马上去载入真正的入口文件(相当于java中的main)。它一般用来对requirejs进行配置,并且载入真正的程序模块。
如果使用相对路径,data-main
有更简单的写法,requirejs会自动下载同级目录下的config.js,完整代码如下:
<!doctype html> <html> <head> <title>requirejs入门(一)</title> <meta charset="utf-8"> <script src="/path/to/require.js" data-main="config"></script> </head> <body> </body> </html>
config.js中有两个函数:require.config和require(或者requirejs.config和requirejs)。
require.config用来配置一些参数,它将影响到requirejs库的一些行为,require.config的参数是一个JS对象,常用的配置有baseUrl
,paths
,urlArgs
等。
首先介绍urlArgs参数,该参数是给每个模块的js文件后附加参数,在调试过程中非常管用,本文所有的案例都添加了该参数以禁用浏览器缓存,等到上线项目再注释掉即可:
urlArgs: "t=" + (new Date()).getTime()
使用require.config通常分为2种情况:一种是支持AMD方式定义的模块,另一种是不支持AMD方式定义的模块。
1. 例如jquery从1.7以后是支持AMD方式的,例如:
require.config({ paths: { "jquery": "jquery-1.7.1.min" }, urlArgs: "t=" + (new Date()).getTime() }); require(["jquery"], function($) { alert($().jquery); });
这里配置了paths
参数,使用模块名“jquery”,其实际文件路径jquery-1.7.1.min.js(后缀.js可以省略)。
如果使用requirejs2.0及以上版本,可以配置一个数组按照顺序加载,例如使用google cdn的jquery库失效时再加载本地的jquery文件。
require.config({ baseUrl: "./", paths: { "jquery": [ "http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min", "jquery-1.7.1.min" ] }, urlArgs: "t=" + (new Date()).getTime() }); require(["jquery"], function($) { alert($().jquery); });
当google cdn无法访问时会引入同级目录下的jquery-1.7.1.min.js。
2. 另一种是不支持AMD方式定义的模块,这时需要使用shim导出他们定义的全局变量,例如:
require.config({ baseUrl: "./", paths: { //左边的是模块的标识(可以随便指定,唯一即可),右边的是模块的文件名 "app": "app" }, shim: { //左边的是模块的标识(key,和paths的标识一致),hello是要暴露的变量(该变量是app.js的全局变量) "app": { exports: "hello" } }, urlArgs: "t=" + (new Date()).getTime() }); require(["app"], function(app) { app(); });
app.js的代码如下:
function hello() { alert("hello world"); }
运行弹出"hello world",如果你去掉shim
方法,你将会得到:Uncaught TypeError: app is not a function。
3. 如果自己写的模块需要暴露2个或以上的变量,这时就不能使用exports
了,必须换成init
方法。
config.js的代码如下:
require.config({ baseUrl: "./", paths: { //左边的是模块标识(可以随便指定,唯一即可),右边的是模块的文件名 "app": "app" }, shim: { "app": { init: function() { return { //注意:左边的是要暴露的变量别名,右边的是要暴露的变量 hello: hello, hello2: hello2 } } } }, urlArgs: "t=" + (new Date()).getTime() }); //注意,第一个参数是数组,其值是需要require的模块,第二个参数是模块对象,对象参数应该与第一个参数是数组元素一一对应 require(["app"], function(app) { //调用模块标识为app的hello和hello2方法 app.hello(); app.hello2(); });
app.js的代码修改如下:
function hello() { alert("hello world"); } function hello2() { alert("hello world, again~"); }
当 exports
与init
同时存在的时候, exports 将被忽略。
通过上面的3个注意可以很清晰看出模块标识,模块对象,模块变量之间的关系。
除了require.config和require之外,requirejs还提供了define方法让我们编写依赖于requirejs的模块(插件),例如我们将app.js按照requirejs的方式来重构代码:
//可以直接使用匿名函数作为define的参数,没有依赖的模块 define(function() { return { "hello": function() { alert("hello world"); }, "hello2": function() { alert("hello world, again~"); } } });
或者
//如果app.js有依赖的模块,可以将各个模块标识以数组作为第一个参数传入,模块对象与匿名函数的参数一一对应 define(["require"], function(require) { return { "hello": function() { alert("hello world"); }, "hello2": function() { alert("hello world, again~"); } } });
重构后就不需要使用shim
方法,也不用担心使用exports
还是init
,直接require后调用即可。
如何完全不让jquery污染全局的$
可以引入 map
配置,一劳永逸地解决这样问题:
map: { // '*' means all modules will get 'jquery-private' // for their 'jquery' dependency. '*': { 'jquery': 'jquery-private'}, // 'jquery-private' wants the real jQuery module // though. If this line was not here, there would // be an unresolvable cyclic dependency. 'jquery-private': { 'jquery': 'jquery'} },
我们可以先新建一个jquery-private.js,定义一个模块,仅仅为了执行这句代码:
define(["jquery"], function(jQuery) { return jQuery.noConflict(true); });
然后在入口处先调用它:
require.config({ baseUrl: "./", paths: { "jquery": "jquery-1.7.1.min", "jquery-private": "jquery-private", "app": "app" }, map: { "*": { "jquery": "jquery-private"}, "jquery-private": { "jquery": "jquery"} }, urlArgs: "t=" + (new Date()).getTime() }); //注意,第一个参数是数组,其值是需要require的模块,第二个参数是模块对象,对象参数应该与第一个参数是数组元素一一对应 require(["jquery", "app"], function($, app) { alert($().jquery); app.hello(); });
以下可以证明在app.js中无法获取到$:
将app.js中的hello方法弹出值改写:
define(["require"], function(require) { return { "hello": function() { alert($().jquery); }, "hello2": function() { alert("hello world, again~"); } } });
再次运行,在hello()方法处会报Uncaught TypeError: $ is not a function错误。
这样,我们就将jquery隔离运行了。如果不信,可以将map段代码去掉,保证弹出2次jquery的版本号。
下一篇主要是介绍requirejs如何配合使用jquery插件。RequireJS学习笔记(二)
本文地址:http://blog.zhengshuiguang.com/js/requirejs-1.html
转载随意,但请附上文章地址:-)
评论已关闭