说到CMD(通用模块加载器),那么不得不使用的它的库seaJs。最近工作中要求使用模块加载器进行项目中,所以对于初学者肯定会遇到很多问题,在这里总结一下,希望能对自己或者他人都是一份收获。
模块加载器使用的好处
- 模块化思想是可以让开发更高效
- 实现模块化需要解决一个任务,这个任务就是依赖关系
- 浏览器端js是天然不能实现模块
- 有一些库弥补了浏览器端JS的一些缺陷,实现了模块化并解决了依赖关系
以seajs为例
在前端开发领域,一个模块,可以是JS 模块,也可以是 CSS 模块,或是 Template 等模块。 而 Sea.js 则专注于 JS 文件模块:
1.模块是一段 JavaScript 代码,具有统一的 基本书写格式
2.模块之间通过基本 交互规则 ,能彼此引用,协同工作
- SeaJS 是一个适用于浏览器环境的 JavaScript 模块加载器
一个库文件,类似于 jQuery
使用这个库提供的规范的模块化的方式来编写 JavaScript 代码
只关心 JavaScript 文件代码模块如何组织
只关心 JavaScript 文件之间如何相互协议、引用、依赖 - SeaJS 的作者是阿里巴巴支付宝前端架构师,花名:玉伯,玉伯也叫射雕
1
2
3
4
5在页面中引入sea.js
通过define()方法来定义模块
通过sea.use()方法来加载、执行模块
通过require()引入模块
通过exports/module.exports暴露模块功能
seajs具体的使用方法(API解释)
1、seajs.use
加载模块,启动模块系统。
* 加载一个模块 seajs.use('id')
* 加载一个模块,在加载完成时,执行回调 seajs.use('id', callback)
* 加载多个模块,加载完成时,执行回调 seajs.use(['id1','id2',...],callback)
* 注意:
· 在调用 seajs.use 之前,需要先引入 sea.js 文件
· seajs.use 与 DOM ready 事件没有任何关系。如果某些操作要确保在 DOM ready 后执行,需要使用 jquery 等类库来保证
· seajs.use 理论上只用于加载启动,不应该出现在 define 中的模块代码里
2、define(factory)
define 是一个全局函数,用来定义模块。
define 接受 factory 参数,factory 可以是一个函数,也可以是一个对象或字符串。
factory 为对象、字符串时,表示模块的接口就是该对象、字符串。
* factory 是一个对象时
· define({})
* factory 是一个字符串时
· define('hello')
* factory 是一个函数时
· define(function(require, exports, module){})
3、require
require 用来加载一个 js 文件模块, require 用来获取指定模块的接口对象 module.exports。
require 在加载和执行的时候,js 会按照同步的方式和执行。
使用注意:
·正确拼写
* 模块 factory 构造方法的第一个参数 必须 命名为 require
·不要修改
* 不要重命名 require 函数,或在任何作用域中给 require 重新赋值
·使用字符串直接量
* require 的参数值 必须 是字符串直接量
Tips: 把 require 看做是语法关键字就好啦
4、模块标识
模块标识是一个字符串,用来标识模块。
- 模块标识可以不包含文件后缀名,比如 .js
- seajs 推荐不加 .js 文件模块后缀
- 模块标识可以是 相对 或 顶级 标识
- 相对标识
相对标识以 . 开头,永远相对于当前模块所处的路径来解析。 顶级标识
顶级标识不以 . 或 / 开始,会相对模块系统的基础路径(base路径,默认是 sea.js 文件所属的路径)。 可以手动配置 base 路径。1
2
3seajs.config({
base: './js'
})普通路径
除了相对和顶级标识之外的标识都是普通路径。 普通路径的解析规则,会相对当前页面解析。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 假设当前页面是 http://example.com/path/to/page/index.html
// 绝对路径是普通路径:
require.resolve('http://cdn.com/js/a');
// => http://cdn.com/js/a.js
// 根路径是普通路径:
require.resolve('/js/b');
// => http://example.com/js/b.js
// use 中的相对路径始终是普通路径:
seajs.use('./c');
// => 加载的是 http://example.com/path/to/page/c.js
seajs.use('../d');
// => 加载的是 http://example.com/path/to/d.js
Tips:
- 顶级标识始终相对 base 基础路径解析。
- 如果不设置,base 路径默认就是 sea.js 库文件所属的路径
- 可以通过 seajs.config({ base: ‘基础路径’ }) 来配置基础路径
- 绝对路径和根路径始终相对当前页面解析。
- 相对标识永远相对于当前文件
- seajs.use 中的相对路径始终相对当前页面来解析。
5、 module
module 是一个对象,上面存储了与当前模块相关联的一些属性和方法。
module.id
- 模块的唯一标识,可以通过
define
方法的第一个参数来指定,默认为该模块文件的绝对路径
- 模块的唯一标识,可以通过
module.uri
- 模块的绝对路径
module.dependencies
- dependencies 是一个数组,表示当前模块的依赖
module.exports
- 当前模块对外提供的接口对象
- 相当于每个模块内部最终都执行了这么一句话:
return module.exports
- 模块与模块之间的通信接口
6、 exports
exports 仅仅是 module.exports 的一个引用。
也就是说修改了 exports 就相当于修改了 module.exports。
但是一旦在 factory 内部给 exports 重新赋值,并不会改变 module.exports 的值。
因此给 exports 赋值是无效的。
7、 exports 和 module.exports 的区别
- 每个模块内部对外到处的接口对象始终都是
module.exports
- 可以通过修改
module.exports
或给它赋值改变模块接口对象 exports
是module.exports
的一个引用,就好比在每一个模块定义最开始的地方写了这么一句代码:var exports = module.exports
关于这俩哥们儿的区别请分析一下代码:
1 | var module = { |
那为啥要有 exports
?
为了开发体验,API更友好,使用 exports 的时候,可以少写一个点儿。
如果你实在分不清楚 exports
和 module.exports
之间的区别,就只记得 module.exports
就可以了。
8、如何将一个普通的模块文件改造为兼容 CMD 规范的模块
1 | if (typeof define === "function" && define.cmd) { |
9、高级配置 seajs.config(options)
可以对 Sea.js 进行配置,让模块编写、开发调试更方便。
1 | seajs.config({ |
那么现在了解了这么多,就上手做一下练习吧。
现在需求是这样的,利用模块加载器的方式,引入jquery模块以及jquery的插件等,并利用他们的功能完成一些功能。
我的demo结构:
step1:引入seajs文件1
2 <!-- 模块加载器 -->
<script src="../public/libs/sea.js"></script>
step2:使用顶级标识配置路径1
2
3
4
5
6
7seajs.config({
base: '../public/assets',
alias: {
jquery: 'jquery',
fullpage:'jquery.fullPage.js'
}
});
step3:在main.js中定义一个模块,引入jquery或者jquery插件(我这里引入的jquery.fullpage.js插件)
下面就是main模块的代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24define(function (require, exports, module) {
// 相对路径,是相对当前模块来说的
// var $ = require('../assets/jquery');
// 顶级路径
var $ = require('jquery1');
// 这里使用的相对标识
// require('../assets/jquery.fullPage');
// 或者使用顶级标识(要在sea.config中配置一下)
require('fullpage');
$('.box').fullpage();
// 在现实开发中需要将一些第三方的库“改装”成模块
// 大多数第三库是支持requirejs
// 使用jQuery 做一个小例子
$('button').click(function () {
$('.box').animate({
width: 300,
height: 300
}, 400);
})
});
注意:记得引入Jquery插件的时候要先查看Jquery插件是否支持CMD,如果不支持的话,要自己手动的在插件源代码中配置1
2
3
4
5
6if(typeof define === 'function' && define.cmd) {
define(function (require) {
var $ = require('jquery');
factory($);
});
}
step4:加载main模块1
seajs.use('../public/scripts/main');