今天想记录一下RequireJS的学习笔记。
RequireJS是一个模块化加载js文件的框架,基于AMD规范实现,可以很方便的实现js文件的异步加载。
想像一下我们的html文件中有很多js文件需要引入进来,如果不使用RequireJS,那么应该会是如下的写法:
<script type="text/javascript" src="a.js"></script>
<script type="text/javascript" src="b.js"></script>
<script type="text/javascript" src="c.js"></script>
<script type="text/javascript" src="d.js"></script>
<script type="text/javascript" src="e.js"></script>
上面的这种写法,虽然可以实现引入js文件,执行js代码的目的,但是仍然存在很多问题:
1、比如在a.js和b.js中定义了相同的变量,那么这两个相同的变量就会出现冲突
2、如果这些js文件都是从网络上的资源中加载,假如a.js在加载过程中出现网络堵塞,一时没加载出来,那么后面的b.js、c.js等文件都不会得到加载,非得等到前面的js文件加载完毕后,才能加载后面的js文件
如果使用RequireJS来加载js文件,由于RequireJS采用的异步加载,所以问题2就能得到解决,前一个js文件没加载完毕,不会影响后一个js文件的加载,而且,使用RequireJS加载的js文件,相当于在一个独立的命名空间中,所以即使js文件中出现相同的变量,也不会产生冲突,问题1也能得到解决。
RequireJS还有很多其他的优点,比如模块化的js让代码重用能力得到提高,让团队协作开发更便利等等。
所以RequireJS是非常值得前端的同学学习的,下面我就记录一下RequireJS的基础的用法。
我们的Demo项目结构如下图所示:
其中:
1、js目录存放的是所有的js文件
2、js/app目录存放的是我们自定义的模块js文件
3、js/lib目录存放的是一些已经实现的js框架文件如jquery、react等
4、require.min.js是RequireJS框架的主文件
5、main.js是当require框架文件加载完毕后,首先执行的代码文件,类似于C语言中的main函数
6、index.html是使用RequireJS模块化加载js文件的网页
在html中加载requirejs
下面是index.html文件的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
<h1>Hello World!</h1>
<script type="text/javascript" data-main="js/main" src="js/require.min.js"></script>
<script type="text/javascript">
require(['app/a'], function(obj) {
document.write('name: ' + obj.name + ', age: ' + obj.age);
});
</script>
</body>
</html>
要在html页面中使用RequireJS,需要先引入requirejs的文件:
<script type="text/javascript" data-main="js/main" src="js/require.min.js"></script>
其中src指定了requirejs文件的路径,这里的加载方式和普通的引入js文件的方式一样,data-main属性指定了requirejs加载完毕后首先要执行的代码,注意data-main属性的值是“js/main”,表示当requirejs加载完毕后,需要执行js目录下的main.js文件。data-main中指定的js文件不需要带文件后缀.js,不过写上好像也没关系。在main.js文件中,一般都是做一些requirejs的配置,
配置RequireJS的参数
如下main.js的代码所示:
require.config({
baseUrl: 'js/lib',
paths: {
app: '../app'
}
})
使用require.config()方法为requirejs框架配置一些属性,如上面代码中配置的baseUrl和paths。其中:
1、baseUrl属性指定了一个默认的路径,配置了该属性后,requirejs框架加载的所有js文件,都是以这个路径为基准的
2、paths属性指定了一系列的键值对,可以很方便地为一些较长的文件路径设置一个短的别名,例如下面的代码:
paths : {
"jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery"]
}
即用jquery代表了http://libs.baidu.com/jquery/2.0.3/jquery路径。
使用RequireJS加载模块
当我们需要加载jquery时,可以使用如下代码:
require(['jquery'], function($) {
//加载jquery完毕
})
当我们需要加载自定义的a.js模块时,在我们上面的main.js中,paths里定义了一个app,值为‘../app’,即表示使用app代替路径’../app’,注意这里的‘../app’路径是相对于baseUrl中指定的路径的,可以用如下代码来加载a.js模块:
require(['app/a'], function() {
//这里的'app/a'就相当于加载了'js/app/a.js'文件,注意这里的'app/a'是不带文件后缀.js的,而且也不允许带后缀,否则无法正确加载js文件
})
上面写了这么多,初学者可能还不知道下面这段代码的意思:
require(['app/a'], function() {
})
这段代码表示加载’app/a’这个模块,require()方法的第一个参数必须是一个数组,哪怕仅仅只加载一个模块;第二个参数是一个回调函数,当模块成功加载后得到执行。
如何编写自定义的模块
编写自定义的模块时,我们也需要遵循AMD规范,下面分类说明:
1、自定义一个对象:
我们的a.js文件代码如下:
define({
name: 'zhangsan',
age: 18
})
要定义一个可以被RequireJS加载的模块,需要使用define()方法来完成,要定义一个对象模块,直接在define()方法中传入这个对象即可,在加载并使用这个对象时,代码如下:
require(['app/a'], function(obj) {
document.write('name: ' + obj.name + ', age: ' + obj.age);
});
回调函数中的obj参数就代表了我们在define()中传入的对象,所以我们可以直接使用obj.name和obj.age来访问这个对象的属性。
2、自定义一个没有任何依赖的方法:
我们的a.js文件代码如下:
define(function() {
var name = 'zhangsan';
var age = 20;
var sayHello = function(name, age) {
document.write('hello, my name is: ' + name + ', my age is: ' + age);
}
sayHello(name, age);
})
要定义一个函数模块,只需在define()的参数中传入一个函数function即可,在使用这个模块时,代码如下:
require(['app/a'], function() {
});
上面的代码在加载完毕a模块后,会自动执行a.js中定义的函数,打开浏览器后结果如下图所示:
3、自定义一个有依赖的方法:
我们的a.js文件代码如下:
define(['jquery'], function($) {
$('h1').css('color', 'red');
})
同时,在main.js中的paths中,加入如下配置:
"jquery": ["http://libs.baidu.com/jquery/2.0.3/jquery"]
然后在index.html文件中加载a模块:
require(['app/a'], function() {
});
可以在浏览器中看到如下图所示:
a.js文件中的define()方法带有两个参数,第一个参数为一个数组,表示这个模块依赖的其他模块,由于在main.js配置文件中配置了jquery,所以a模块中依赖的jquery会被加载,加载完毕后,在define()方法的第二个参数,也就是回调函数中,使用加载好的jquery,用$获取h1标签,然后将h1标签变成红色。
4、将一个方法作为模块:
我们的a.js文件代码如下:
define(function() {
return function(a, b) {
return a + b;
}
})
define()方法中传入了一个function,该function的返回值为一个function,传入两个参数a,b,然后返回a + b的值。
然后在index.html文件中加载a模块:
require(['app/a'], function(add) {
document.write('3 + 2 = ' + add(3, 2));
});
在浏览器中访问Index页面后结果如下图:
5、简单包装CommonJS来定义模块:
我们的a.js文件代码如下:
define(function(require, exports, modules) {
var a = require('a'),
b = require('b');
//Return the module value
return function () {};
});
该方式定义模块我还没验证,是根据官方文档上来的。。。先记录在此。。。
6、定义一个命名模块:
我们的a.js文件代码如下:
define("app/test", [], function() {
})
define()中有3个参数,分别代表模块名、依赖的模块、回调函数,该方式不推荐使用,因为属于硬编码的模块,不利于模块的扩展和复用。
这一篇笔记先记录到此,后面有需要的话再补充。。。