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 官网 。