本文详解 RequireJS 核心 API 与配置方法。涵盖 define 定义模块、require 加载依赖及回调处理;通过 paths 配置模块路径与 CDN 回退;利用 data-main 实现全局主数据配置。重点讲解使用 shim 处理非 AMD 规范模块(如旧版 jQuery、Underscore)及插件依赖,帮助开发者构建规范的 JS 项目结构。
RequireJS 基础 API 与模块加载
在前一篇介绍 JS 模块化工具的文章中,我们以极简方式引入了 RequireJS:https://www.jb51.net/article/82527.htm。本篇将继续深入讲解 RequireJS 的基础知识,重点包括其 API 的具体使用方式及相关配置。
基本 API
RequireJS 会定义三个全局变量:define、require 和 requirejs。其中 require 与 requirejs 指向同一对象(require === requirejs),通常建议使用更简短的 require。
从命名即可看出,define API 用于定义一个模块;而 require 用于加载依赖模块,并在加载完成后执行回调函数。参考前文中的 a.js 示例:
define(function(){
function fun1(){
alert("it works");
}
fun1();
})
上述代码通过 define 函数定义了一个模块。在页面中使用时,需通过 require 进行加载:
使用 require(["js/a"]) 来加载该模块。需要注意,require 中的依赖参数必须是一个数组,即使只依赖一个模块,也必须使用数组形式定义。require API 的第二个参数是 callback,即一个 function,用于处理加载完毕后的逻辑,例如:
require(["js/a"],function(){
alert("load finished");
})
模块路径配置与 CDN 回退
加载文件
在之前的例子中,加载的模块均为本地 JS 文件。但在实际开发中,网页所需的 JS 可能来自本地服务器、其他网站或 CDN。此时无法直接通过相对路径加载,我们以加载 jQuery 库为例进行说明:
require.config({
paths : {
"jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery"]
}
})
require(["jquery","js/a"],function($){
$(function(){
alert("load finished");
})
})
此处涉及了 require.config。该配置用于指定模块的加载位置,简而言之,即为模块起一个更短、更易记的名称。例如,将百度的 jQuery 库地址标记为 "jquery",这样在 require 时只需写入 ["jquery"] 即可加载该 JS 文件。对于本地 JS,我们也可以采用同样的配置方式:
require.config({
paths : {
"jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery"],
"a" : "js/a"
}
})
require(["jquery","a"],function($){
$(function(){
alert("load finished");
})
})
通过 paths 配置,模块名称变得更加精炼。paths 还有一个重要功能:支持配置多个路径。如果远程 CDN 库加载失败,可以自动回退加载本地库,配置如下:
require.config({
paths : {
"jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery", "js/jquery"],
"a" : "js/a"
}
})
require(["jquery","a"],function($){
$(function(){
alert("load finished");
})
})
完成上述配置后,当百度的 jQuery 加载失败时,系统会自动加载本地 js 目录下的 jquery 文件。
在使用 RequireJS 加载模块时,无需也不能在模块名中写入 .js 后缀。在上述示例的 callback 函数中可以看到 $ 参数,该参数即为依赖的 jQuery 模块输出的变量。如果依赖多个模块,可以依次写入多个参数来使用它们:
require(["jquery","underscore"],function($, _){
$(function(){
_.each([1,2,3],alert);
})
})
如果某个模块没有输出变量值,则对应的参数位置为空。因此,建议将输出变量的模块写在前面,以防止参数位置错乱引发误解。
全局配置与主数据 (data-main)
全局配置
在前面的例子中,require.config 配置反复出现。如果每个页面都单独加入配置,代码显得冗余且不美观。RequireJS 提供了一种名为“主数据”的功能来解决这一问题。我们首先创建一个 main.js 文件:
require.config({
paths : {
"jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery", "js/jquery"],
"a" : "js/a"
}
})
然后在页面中使用以下方式引入 RequireJS:
<script data-main="js/main" src="js/require.js"></script> 这里解释一下,加载 RequireJS 脚本的 script 标签中加入了 data-main 属性。该属性指定的 JS 文件将在 RequireJS 加载完成后执行。我们将 require.config 的配置放入 data-main 指向的文件中,即可使所有页面共享该配置,随后页面中可直接使用 require 加载所有短模块名。
data-main 还有一个重要功能:当 script 标签指定 data-main 属性时,RequireJS 会将 data-main 指定的 JS 所在目录默认为根路径。这是什么意思呢?例如,设定 data-main="js/main" 后,当我们使用 require(['jquery'])(且未配置 jquery 的 paths)时,RequireJS 会自动加载 js/jquery.js 文件,而不是根目录下的 jquery.js。这相当于默认配置了:
require.config({
baseUrl : "js"
})
Shim 处理非 AMD 模块与插件
第三方模块
通过 RequireJS 加载的模块通常需符合 AMD 规范,即使用 define 来声明模块。但在某些情况下,我们需要加载非 AMD 规范的 JS 文件,此时需使用另一个功能:shim。Shim 直译为“垫”,其作用正是如此。目前我主要将其用于以下两个场景: 1. 非 AMD 模块输出:将非标准 AMD 模块“垫”成可用模块。例如,老版本 jQuery 未继承 AMD 规范,不能直接 require["jquery"],此时需借助 shim。比如使用 Underscore 类库,若其未实现 AMD 规范,可这样配置:
require.config({
shim: {
"underscore" : {
exports : "_";
}
}
})
完成上述配置后,我们便可在其他模块中引用 Underscore 模块:
require(["underscore"], function(_){
_.each([1,2,3], alert);
})
2. 插件形式的非 AMD 模块:我们常需使用 jQuery 插件,而这些插件大多不符合 AMD 规范。例如 jquery.form 插件,此时需将 form 插件“垫”到 jQuery 中:
require.config({
shim: {
"underscore" : {
exports : "_";
},
"jquery.form" : {
deps : ["jquery"]
}
}
})
上述配置也可简写为:
require.config({
shim: {
"underscore" : {
exports : "_";
},
"jquery.form" : ["jquery"]
}
})
完成配置后,即可使用加载了插件的 jQuery:
require.config(["jquery", "jquery.form"], function($){
$(function(){
$("#form").ajaxSubmit({...});
})
})
RequireJS 的基本配置大致如上所述。后续篇幅还将介绍其他扩展功能,敬请期待!