requirejs教程
随着前端项目的不断增大,js 文件越来越多,大部分都是 js 的依赖模块,传统的引入方式已经无法满足当前开发需求,急需模块化的方案来替我们管理这些依赖。
但,javascript 天生并不支持模块化,无法将多个模块文件分离出去,在使用时再将多个模块合并起来。事情总是需要解决,也总是不缺乏造轮子的人。
于是,前端模块化的始祖,require.js 出现了,其基于 AMD 规范。使用 define 函数定义模块,利用 require 函数 导入模块。详细使用方式请继续往下看。
获取方式
- 官方地址: https://requirejs.org/
- github: https://github.com/requirejs/requirejs
为什么要使用 require.js?
最早的时候,所有 Javascript 代码都写在一个文件里面,只要加载这一个文件就够了。后来,代码越来越多,一个文件不够了,必须分成多个文件,依次加载。下面的网页代码,相信很多人都见过。
1 | <script src="1.js"></script> |
这段代码依次加载多个 js 文件。
这样的写法有很大的缺点。首先,加载的时候,浏览器会停止网页渲染,加载文件越多,网页失去响应的时间就会越长;其次,由于 js 文件之间存在依赖关系,因此必须严格保证加载顺序(比如上例的1.js 要在 2.js 的前面),依赖性最大的模块一定要放到最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。
require.js 的诞生,就是为了解决这两个问题:
1 | (1)实现js文件的异步加载,避免网页失去响应。 |
模块加载规则
RequireJS 以一个相对于 baseUrl 的地址来加载所有的代码。 即 baseUrl + paths 的解析过程。
baseUrl的确定规则
- 以含有
data-main属性的script的html页面所在文件目录为baseUrl。
页面顶层 <script> 标签含有一个特殊的属性 data-main,require.js使用它来启动脚本加载过程,而baseUrl一般设置到与该属性相一致的目录。
- 以
paths配置为准。(下面会介绍如何配置)
注:RequireJS 默认假定所有的依赖资源都是 js 脚本,因此无需在 module ID 上再加 .js 后缀,RequireJS 在进行 module ID 到 path 的解析时会自动补上后缀。你可以通过 paths config 设置一组脚本,这些有助于我们在使用脚本时码更少的字。
有时候你想避开 baseUrl + paths 的解析过程,而是直接指定加载某一个目录下的脚本。此时可以这样做:如果一个 module ID 符合下述规则之一,其ID解析会避开常规的 baseUrl + paths 配置,而是直接将其加载为一个相对于当前 HTML 文档的脚本:
1 | 1. 以 ".js" 结束. |
文件结构
1 | |-www/ |
login.html
1 | <html> |
dom.js
该模块导出了一个对象。
1 | define(function(){ |
login.js
在 login.js 中,引用了 dom 模块,此时,baseUrl 为 login.html 所在的目录。所以,要想找到 dom.js,需要连跳两层文件夹,再进入 utils文件夹。
1 | require(['../../utils/dom'] , function( dom ){ |
这里有个需要注意的地方,如果你引用了那些定义了 模块名 的文件,是无法保证主逻辑文件和依赖文件的加载顺序的,也就是说,你很有可能获取不到依赖文件导出的变量。例如 jquery.js ,其内部 定义模块时,加上了模块名参数 jquery。
1 | define("jquery" , function(){ |
基于这种情况,require.js 会根据 paths 配置查找文件路径 (关于配置下面会介绍)。如果没有配置 paths 的话,require.js 只会简单的将该依赖文件通过含有 async 属性的 <script> 标签加载到 <head> 中,并不会处理文件之间的依赖关系。所以,当你引用一个含有模块名定义的依赖,又没有为其配置 paths 时,就会出现如下状况:
1 | // login.js |
所以此时,我们需要对依赖进行配置 paths:
1 | // login.js |
现在,我们就可以拿到 jquery 导出的全局变量 $ 了。
API介绍
data-main属性
指定页面主逻辑文件的的路径,它有点像 c语言 中 main()函数,所有的代码都从这开始运行。同时,它也默认确定了 baseUrl 的值为当前页面所在的目录。
require.config()配置方法
require.config.js文件:
1 | require.config({ |
define() 函数
AMD 规范要求 ,定义一个模块时 ,必须使用 define() 函数 来进行模块的 定义。
define 函数的参数说明
在定义一个模块时,其实 define 函数 接受 3个 参数。
参数1 : String类型,定义该模块的名字(一般不会写这个参数,使用路径的方式引用模块更易控)
参数2 : Array类型,该模块依赖,使用配置好的路径别名 或 路径
参数3 : callback, 该模块的主逻辑体 , callback 回调函数的 可接收 一些参数,这些参数就是 该模块的依赖项所导出的模块变量
值得注意的是,你需要按照 参数2 模块依赖 数组中参数的顺序来 配置 回调函数 的 形参顺序。
@returns : 任意类型,指定定义模块导出的接口。
例:
定义了一个 foo 模块,该模块依赖于 jquery
输出打印了一些信息
导出了一个对象
1 | define(['jquery'] , function($){ |
require() 函数
有定义,就有引用,AMD规范中,使用 require() 函数 来引用模块。
require 函数的参数说明
参数1 : Array类型,模块依赖
参数2 : callback , 主体逻辑
例:
1 | require(['jquery' , 'foo'] , function( $ ){ |
最佳实践
在多页面应用中,每个页面都会对应一个主逻辑文件,那如果,我们每次都在 *.js 文件头部写配置信息的话,那就太蠢了。效率低下而不优雅。
所以,在项目根目录下,创建一个 require.config.js 文件,将配置信息写在这个文件中。当然,文件名你可以随便定义,最好能够区分她是谁的配置文件。
对于多页应用来说,通常我们会有如下项目结构:
1 |
|
那么我们会这样使用模块化。
demo.html
1 | <html> |
require.config.js
1 | require.config({ |
demo.js
1 | require(['jquery' , 'dom'] , function($ , dom){ |
也许你会想,哇!这不还是加载了 3 个 script 标签引用吗?
-- || 当你有 100 个 js 文件依赖时,你就不会这么想了!不信你可以试试。祝你好运!
兼容性
1 | IE 6+ .......... 兼容 ✔ |
结束语
这篇文章仅记录 require.js 的简单使用,可以帮助你快速入门,一般项目开发足够了,需要更多有关 require.js 的信息,可以翻阅 requirejs 官网 。