前端模块化(五):RequireJs
1 概述
RequireJS是一个JS模块加载器,遵循AMD规范。它主要是为了实现JS文件的异步加载以及管理模块之间的依赖性。下面,我们通过一下例子来了解requirejs的使用。
2 RequireJs的使用
首先,我们创建一个项目,主要文件目录如下:
2.1 加载模块
在使用requieJS模块化开发之前,我们需要下载require.js,可以通过npm下载或者在官网获得。然后,创建两个文件index.html以及index.js,示例代码一如下:
//index.html <!DOCTYPE html> <html> <head > <title>require栗子</title> </head> <body> <div> <h1>这是require栗子</h1> <button id="clickBtn">点击展开</button> <p id="showMsg"></p> </div> <script data-main="js/ctr/index" src="js/lib/require.js" type="text/javascript"></script> </body> </html>
//js/ctr/index.js require.config({ paths: { 'jquery': '../lib/jquery' } }); require(['jquery'], function($) { $(document).on('click', '#clickBtn', function() { $('#showMsg').html('看看jquery加载进来了没有'); }); });
使用<script>标签来引入requireJS,这个是毫无疑问的。然后在<script>标签中发现有个data-main属性,这是什么意思呢?在index.js文件中出现的require.config以及require有什么作用呢?下面,我们逐一分析一下。
2.1.1 data-main
data-main属性,它的作用是作为一个出入口,指定入口主模块。也就是说,require.js会在加载完成以后通过回调方法去加载这个data-main里面的js文件,所以这个js文件被加载的时候,RequireJS已经加载执行完毕。在示例代码一中,加载完requirejs后,便会根据data-main属性加载js/ctr/index.js文件。
data-main还有一个重要的功能,当script标签指定data-main属性时,require会默认的将data-main指定的js为根路径。在上面的实例代码一中,把js/ctr作为了根目录,相当于默认设置了配置,示例代码二如下:
require.config({ baseUrl : "js" })
当然,这个默认设置被index.js里面的require.config配置所覆盖,所以没有生效。
2.1.2 require.config
require.config的作用就是配置requireJS的一些参数,然后公共引用。config函数需要传入一个可选参数对象,这个可选参数对象包括了许多的配置参数选项。这些配置参数选项的主要作用如下:
- baseUrl——用于加载模块的根路径。
- paths——用于映射不存在根路径下面的模块路径。
- shims——配置在脚本/模块外面并没有使用RequireJS的函数依赖并且初始化函数。
- deps——加载依赖关系数组
在示例代码一中,我们定义了jquery文件的路径,设置了模块名为‘jquery’。 这里,require是以当前主模块index.js路径为起点去寻找jquery.js文件的,所以在paths配置项中,我们设置的jquery路径要‘../’回到上级目录才能寻找到jquery。在主模块中,调用的时候可以直接使用模块名‘jquey’,require会根据config配置项中定义的路径去加载js/lib/jquery.js。require.config的配置项优先权高于data-main,可以覆盖data-main的默认配置。
2.1.3 require
require函数用于加载模块依赖但并不会创建一个模块。
require()函数接受两个参数。第一个参数是一个数组,表示所依赖的模块,上例就是['jquery'],即主模块依赖这个模块;第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块。
在上面的实例代码一中,require函数异步加载了jquery模块,浏览器不会失去响应;它指定的回调函数,只有前面的模块都加载成功后,才会运行,由此解决了模块依赖性的问题。
2.1.4 加载扩展
在示例代码一中,把require.config()放在index.js里面,这样子不够优雅。我们应该把require.config()抽出来,单独放在一个js文件里面,这样方便移植和复用。下面,我们修改idnex.js,把require.config()抽出来放在js/ctr/config.js中。示例代码三如下:
// js/ctr/config.js总配置文件 define(function () { require.config({ paths: { 'jquery': '../lib/jquery' } }); })
// js/ctr/index.js require(['config'],function(){//加载配置文件 require(['jquery'], function($) { $(document).on('click', '#clickBtn', function() { $('#showMsg').html('看看jquery加载进来了没有'); }); }); })
2.2 define模块定义
require.js加载的模块,采用AMD规范。也就是说,模块必须按照AMD的规定来写。
具体来说,就是模块必须采用特定的define()函数来定义。如果一个模块不依赖其他模块,那么可以直接定义在define()函数之中。
创建一个文件a.js,它定义了一个modA模块。示例代码四如下:
//js/ctr/a.js define(function (){ var funA = function (x,y){ return x+y; }; return { funA: funA }; });
//js/ctr/index.js require(['jquery', 'a'], function ($ ,modA){ $(document).on('click', '#clickBtn', function() { $('#showMsg').html('看看jquery加载进来了没有'); }); console.log(modA.funA (1,1));//在控制台输出结果2 });
2.3 加载非AMD规范的模块
通过require加载的模块一般都需要符合AMD规范即使用define来申明模块,但是部分时候需要加载非AMD规范的js,这时候就需要用到另一个功能:shim。shim是require.config配置对象中的一个属性,专门用来配置不兼容的模块。具体来说,每个非AMD规范模块要定义exports值和deps数组。
(1)exports值(输出的变量名),表明这个模块外部调用时的名称。我们有时候会用到underscore类库,但是他并没有实现AMD规范,那我们可以这样配置,示例代码五如下:
require.config({ shim: { "underscore" : { exports : "_"; } } })
这样配置后,我们就可以在其他模块中引用underscore模块,示例代码六如下:
require(["underscore"], function(_){ _.each([1,2,3], alert); })
(2)deps数组,表明该模块的依赖性。例如,我们经常会用到jquery插件,而且这些插件基本都不符合AMD规范,比如jquery.form插件,这时候就需要将form插件"垫"到jquery中,示例代码七如下:
require.config({ shim: { "jquery.form" : { deps : ["jquery"], exports: 'jqueryForm' } } })
3 总结
本文对RequireJS的使用做了简单的介绍,大家如有需要对RequireJS进行更深入的了解,可以直接看源码或者查看官方API文档。下一篇我们开始介绍CMD规范,进一步了解模块化的演进。