模块化与requirejs
前面一篇文章写过一些模块的原理和怎么实现模块化,但是在具体的项目当中怎么实现呢。我们这里介绍下require的使用。
在介绍require之前,先简单的介绍下AMD和CMD。
AMD(Asynchronous Module Definition),CMD(Common Module Definition)这是这两个词的全称,看起来就是模块的定义的区别,实际上也就是在具体的应用中模块定义的位置不同。下面我们介绍require,完了应该对模块定义的位置能有一些理解。
就像上篇文章说的,我们实现了模块化,将不同的模块定义成不同的对象,不同的模块之前互不影响,而且我们还可以去引入一些模块的依赖关系而不是全部的一股脑的引入。require就是为了实现模块化的一个工具。那么使用require有哪些优点呢?
1、异步加载,我们知道js加载放到页面之前会阻塞页面,requirejs的执行时在异步的回调函数里,不会阻塞页面
2、模块的依赖,我们可以方便的管理依赖
3、面向对象,通过模块化我们可以方便的实现面向对象
4、文件管理,当我们的依赖发生变化或者文件变化时不再需要到每一个文件里去改变这个引用,只要在改一处即可,因为其他地方都是对我们模块定义的引用。
当然还有一些其他的优点,刚开始接触也就先介绍这一些了,下面我们来看怎么使用require
1、引入
首先得第一步的先下载require并引入到页面
<script data-main='js/config.js' src='js/require.js'></script>
require.js 是我们下载的require,那么config呢,当然很多也用main.js只是名字而已,只是觉得用config语义看起来明确,没错就是配置文件。这里的config.js可以省略后缀。
requirejs提供三个方法,requirejs,require和define,前两个是一样的,一般用require,我们看一个config文件
/*require.config
baseUrl为'js',
baseUrl指的模块文件的根目录,可以是绝对路径或相对路径
*/
require.config({
baseUrl:'js',
paths: {
jquery:'jquery-1.8.2.min',
moduleA:'a.js'
}
});
require.config时配置模块得一些信息,这里面有两个属性
baseUrl我们定义的目录,表示下面的一些文件可以从这个目录开始。
paths是一个对象,这里面就是定义我们项目中的模块了。前面属性名(key值)是模块的名字,后面的属性(value)是模块的文件位置.
2、模块的定义
上面我们定义了模块的信息,那么这些模块的js应该怎么写来实现require的使用呢。就是用到了define方法来定义模块。我们来看一个模块的定义。
/*define的参数为匿名函数,该匿名函数返回一个对象*/
define(['jquery'],function($){
return {
a: function(){
$("body").append("模块A加载......");
}
}
})
define为定义模块的方法,有三个参数,第一个参数为模块名,一般都不用定义,第二个是数组,是当前模块的依赖,是否依赖其他的模块,第三个参数为回调函数,一般返回值为对象。
3、模块的定义和引入是完成了下面就是模块的使用了,我们看一个模块的使用
index.js
require(['config'],function(){
require(["jquery",'a','b','c'],function($,ma,mb,mc){
ma.a();
mb.a();
mc.a();
})
})
最外层是应用config的配置,内层是模块的使用,前面数组是依赖或者引入的模块,函数的参数是这个引入的模块的应用时的名字,函数内是模块内函数的调用。
当然如果直接把模块的使用写在config的文件内,可以不需要声明config的调用。
那么是使用require的时候,我们要调用的模块必须要符合require使用的模块的要求,jquery源码里有这么一段,所以jquery我们直接使用
if ( typeof define === "function" && define.amd ) {
define( "jquery", [], function() {
return jQuery;
});
}
那么其他的没有按照这种要求写的模块我们怎么使用呢,这里就要用到shim。
require.config()接受一个配置对象,这个对象除了有前面说过的paths属性之外,还有一个shim属性,专门用来配置不兼容的模块。具体来说,每个模块要定义(1)exports值(输出的变量名),表明这个模块外部调用时的名称;(2)deps数组,表明该模块的依赖性。
比如上面的moduleA,如果我们这样写
define(['jquery'],function($){
return {
a: function(){
$("body").append("模块A加载......");
}
}
})
这样写的方式符合require模块的写法可以直接使用。
如果我们这样写呢
o = {
a:function(){
$("body").append("模块A加载......");
}
}
也就是在这个js里只写了个对象,并没有返回也没有define。
那么在config里我们就需要用到这样的配置
require.config({
baseUrl: 'js',
paths:{
"jquery":"jquery-2.1.0",
"moduleA":"a",
},
shim:{
'moduleA':{
deps:['jquery'],
exports:'o'
}
}
})
shim的deps是这个模块的依赖模块的引入,exports是这个A模块所要使用的返回值。后面的使用不变。
在简单些,如果我们将A写成这样
function a(){
$("body").append("模块A加载......");
}
只是一个函数的定义呢,那么我们的shim里exports就要写成
shim:{
'moduleA':{
deps:['jquery'],
exports:'a'
}
}
这时候模块A就是一个函数而已而不是一个对象了。
这里我们在看下AMD和CMD,这里我们的模块的引入都是在使用之前将全部的依赖的模块引入,AMD的依赖引入是提前执行,CMD则是就近执行,即在使用的时候执行。
参考文档