2、解决模块之间的依赖问题.
二、API 快速参考
一、seajs.config
用来对 Sea.js 进行配置。
1 seajs.config({
2
3 // 设置路径,方便跨目录调用
4 paths: {
5 'arale': 'https://a.alipayobjects.com/arale',
6 'jquery': 'https://a.alipayobjects.com/jquery'
7 },
8
9 // 设置别名,方便调用
10 alias: {
11 'class': 'arale/class/1.0.0/class',
12 'jquery': 'jquery/jquery/1.10.1/jquery'
13 }
14
15 });
二、seajs.use
用来在页面中加载一个或多个模块。
1 // 加载一个模块
2 seajs.use('./a');
3
4 // 加载一个模块,在加载完成时,执行回调
5 seajs.use('./a', function(a) {
6 a.doSomething();
7 });
8
9 // 加载多个模块,在加载完成时,执行回调
10 seajs.use(['./a', './b'], function(a, b) {
11 a.doSomething();
12 b.doSomething();
13 });
三、define
用来定义模块。Sea.js 推崇一个模块一个文件,遵循统一的写法:
1 define(function(require, exports, module) {
2
3 // 模块代码
4
5 });
require
, exports
和 module
三个参数可酌情省略,具体用法如下。
四、require
require
用来获取指定模块的接口。
1 define(function(require) {
2
3 // 获取模块 a 的接口
4 var a = require('./a');
5
6 // 调用模块 a 的方法
7 a.doSomething();
8 });
注意,require
只接受字符串直接量作为参数
五、require.async
用来在模块内部异步加载一个或多个模块。
1 define(function(require) {
2
3 // 异步加载一个模块,在加载完成时,执行回调
4 require.async('./b', function(b) {
5 b.doSomething();
6 });
7
8 // 异步加载多个模块,在加载完成时,执行回调
9 require.async(['./c', './d'], function(c, d) {
10 c.doSomething();
11 d.doSomething();
12 });
13
14 });
六、exports
用来在模块内部对外提供接口。
1 define(function(require, exports) {
2
3 // 对外提供 foo 属性
4 exports.foo = 'bar';
5
6 // 对外提供 doSomething 方法
7 exports.doSomething = function() {};
8
9 });
七、module.exports
与 exports
类似,用来在模块内部对外提供接口。
1 define(function(require, exports, module) {
2
3 // 对外提供接口
4 module.exports = {
5 name: 'a',
6 doSomething: function() {};
7 };
8
9 });
module.exports
与 exports
的区别
以上 7 个接口是最常用的,要牢记于心。
---------------------------------------------------------------------------------------------------------------------------------------
四、seajs模块依赖的加载处理
最近在做项目的时候发现一些关于模块依赖问题,特记录下:
比如现有3个文件:
1 /*init.js*/
2 define(function(require, exports, module){
3 require('jquery');
4 require('jquery.plugA');
5 })
6
7 /*jquery.plugA.js*/
8 define(function(require, exports, module){
9 require('jquery');
10 require('jquery.plugB');
11 //code...
12 })
13
14 /*jquery.plugB.js*/
15 define(functioin(require, exports, module){
16 require('jquery');
17 //code...
18 })
比如执行init.js时,init.js、jquery.plugA.js、jquery.plugB.js都会依赖到jquery,那么这种情况下seajs对jquery如何处理的呢?只执行一次?执行多次?还是其他方式?
此处参考玉伯的回答:
我对模块调用的理解是,调用是指获取某个模块的接口。在 SeaJS 里,只有 seajs.use, require.async, 和 require 会产生
模块调用,比如: var a = require('./a')
在执行 require(‘./a’) 时,会获取模块的接口,如果是第一次调用,会初始化模块 a,以后再调用时,直接返回模块 a 的接口 define 只是注册模块信息,比如打包之后: define(id, deps, factory)
是注册了一个模块到 seajs.cache 中,define 类似: seajs.cache[id] = { id: id, dependencies: deps, factory: factory }
是纯注册信息。
而 require('./a')
时,才会执行 seajs.cache['a'].factory
, 执行后得到 seajs.cache['a'].exports
扩展:URI与URL的区别
URI:Uniform Resource Identifiers ,统一资源标识符;
URL:Uniform Resource Locators ,统一资源定位符;
URN:Uniform Resource Names,统一资源名称
URL,URN是URI的子集.
五、seajs实战参考
该页面列举了 SeaJS 中的常用实战过程中的问题。只要掌握这些方法,就可以娴熟地开始对你的网站进行模块化开发了。
默认情况下,SeaJS 要求所有文件都是标准的 CMD 模块,但现实场景下,有大量 jQuery 插件等非 CMD 模块存在。在 SeaJS 里,通过以下方式,可以直接调用非标准模块。
全站通用的要加载的库只写一次,而不想每个js里都调用,太繁琐
1 //可以放在在 init.js 里暴露到全局,这样,所有在 init.js 之后载入的文件,就都可以直接通过全局变量来拿 $ 等对象。
2
3 seajs.use('init')
4
5 //init.js
6 define(function(require, exports) {
7 var $ = jQuery = require('jquery');
8
9 // 暴露到全局
10 window.$ = $;
11 });
1. 暴露 jQuery
jQuery 插件都依赖 jQuery 模块,为了加载 jQuery 插件,首先得将 jQuery 模块暴露出来:
1 // 配置 jquery 并放入预加载项中
2 seajs.config({
3 alias: {
4 'jquery': 'https://a.alipayobjects.com/static/arale/jquery/1.7.2/jquery.js'
5 },
6 preload: ["jquery"]
7 })
8
9 // 将 jQuery 暴露到全局
10 seajs.modify('jquery', function(require, exports) {
11 window.jQuery = window.$ = exports
12 })
2. 修改 jQuery 插件的接口
我们以 jquery.cookie 插件为例。
1 // 配置别名
2 seajs.config({
3 alias: {
4 'cookie': 'https://raw.github.com/carhartl/jquery-cookie/master/jquery.cookie.js'
5 }
6 })
7
8 // 将 jQuery Cookie 插件自动包装成 CMD 接口
9 seajs.modify('cookie', function(require, exports, module) {
10 module.exports = $.cookie
11 })
3. 调用 Cookie 插件
这样,在其他模块中,就可以直接调用 cookie 插件了:
1 a.js:
2
3 define(function(require, exports) {
4 var cookie = require('cookie')
5
6 cookie('the_cookie')
7 cookie('the_cookie', 'the_value')
8
9 // ...
10 })
seajs里版本号和时间戳问题
用 seajs 组织项目,上线后,经常需要更新特定文件或所有文件的时间戳,以清空浏览器缓存。最简单的方式是:
1 //用来维护 jquery 等类库模块的版本号
2 seajs.config({
3 alias: {
4 'jquery': 'jquery/1.6.2/jquery',
5 'backbone': 'backbone/0.5.1/backbone',
6 'a': 'a.js?20110801',
7 'b': 'b.js?20110801'
8 }
9 });
10
11 //利用 map,批量更新时间戳是最方便的
12 seajs.config({
13 'map': [
14 [ /^(.*.(?:css|js))(.*)$/i, '$1?20110801' ]
15 ]
16 });
条件加载
第一种:把依赖的模块都在 define 头部手工声明,不再依赖 SeaJS 的自动解析功能。这个模块同时依赖 play 和 work 两个模块,加载器会把这两个模块文件都下载下来。如果需要在 require 模块之后串行执行代码,那么只能用这个方式。
1 define(['play', 'work'], function(require, exports) {
2 //是出去玩,还是工作?
3 var choice = require(condition() ? 'play' : 'work');
4 //选择的难度
5 console.log(choice.hard());
6 });
第二种:使用 require.async 来进行条件加载,从静态分析的角度来看,require.async适合需要执行动态加载的模块很大(比如大量 json 数据),不适合都下载下来。但是require.async 方式加载的模块,不能打包工具找到,自然也不能被打包进上线的 js 中;而前一种方式可以。
1 define(function(require, exports) {
2 require.async(condition() ? 'play' : 'work', function(choice) {
3 console.log(choice.hard());
4 });
5 });
按需加载
很多时候模块并不需要立即加载,等到需要时再加载,性能更好。
1 //init.js
2 $("#J_PicCover").click(function(){
3 require.async('module/highlight', function(){
4 $(".buy-info").highlight({color:'#ffe5c4',speed:500,complete:function(){
5 },iterator:'sinusoidal'});
6 });
7 });
8
9 //highlight.js
10 define(function(require, exports) {
11 jQuery.fn.highlight = function(settings) {
12 //…...
13 }
14 });
六、seajs快速参考
该页面列举了 SeaJS 中的常用 API。只要掌握这些方法,就可以娴熟地进行模块化开发。
启动模块系统
1 <script src="http://modules.seajs.org/seajs/1.2.0/sea.js"></script>
2 <script>
3 seajs.use('./main');
4 seajs.use(['./a', './b'], function(a, b) {
5 a.init();
6 b.init();
7 });
8 </script>
9
10 //callback 参数是可选的。当只启动加载一个模块,且不需要 callback 时,可以用 data-main 属性来简化:
11 <script src="http://modules.seajs.org/seajs/1.2.0/sea.js" data-main="./main"></script>
12
13 /*
14 引入 sea.js 时,可以把 sea.js 与其他文件打包在一起,提前打包好,或利用 combo 服务动态打包。
15 无论哪一种方式,为了让 sea.js 内部能快速获取到自身路径,推荐手动加上 id 属性:
16 加上 seajsnode 值,可以让 sea.js 直接获取到自身路径,而不需要通过其他机制去自动获取。
17 这对性能和稳定性会有一定提升,推荐默认都加上。
18 */
19 <script src="path/to/sea.js" id="seajsnode"></script>
seajs.config
1 //seajs.config 可以叠加,可以在多处调用,同名 key 覆盖,不同名的 key 叠加。这样可以做到:区域配置可以覆盖通用配置或可以说在区域配置中可对 seajs config 再做按需配置而不会影响到通用配置。
2 seajs.config({
3
4 //alias最常用来做版本配置与管理,也可以用来做命名空间管理。
5 alias: {
6 'es5-safe': 'es5-safe/0.9.2/es5-safe',
7 'json': 'json/1.0.1/json',
8 'jquery': 'jquery/1.7.2/jquery'
9 },
10
11 /*
12 使用 preload 配置项,可以在普通模块加载前,提前加载并初始化好指定模块。
13 注意:preload 中的配置,需要等到 use 时才加载。
14 preload 配置不能放在模块文件里面
15 */
16 preload: [
17 Function.prototype.bind ? '' : 'es5-safe',
18 this.JSON ? '' : 'json'
19 ],
20
21 //值为 true 时,加载器会使用 console.log 输出所有错误和调试信息。 默认为 false, 只输出关键信息
22 debug: true,
23
24 //该配置可将某个文件映射到另一个。可用于在线调试,非常方便。
25 map: [
26 ['http://example.com/js/app/', 'http://localhost/js/app/']
27 ],
28
29 /*
30 SeaJS 在解析顶级标识时,会相对 base 路径来解析。
31 注意:一般请不要配置 base 路径,保持默认往往最好最方便。
32 base 路径的默认值,与 sea.js 的访问路径相关:
33 如果 sea.js 的访问路径是:
34 http://example.com/js/libs/sea.js
35 则 默认base 路径为:
36 http://example.com/js/libs/
37 */
38 base: 'http://example.com/path/to/base/',
39
40 //获取模块文件时,<script> 或 <link> 标签的 charset 属性。 默认是 utf-8 。
41 charset: 'utf-8'
42 });
seajs.use
1 /*
2 模块加载器
3 seajs.use 理论上只用于加载启动,不应该出现在 define 中的模块代码里。在模块代码里需要异步加载其他模块时,可以使用 require.async 方法。
4 */
5
6 seajs.use('./a');
7
8 seajs.use('./a', function(a) {
9 a.doSomething();
10 });
11
12 seajs.use(['./a', './b'], function(a, b) {
13 a.doSomething();
14 b.doSomething();
15 });
16
17 //seajs.use 与 dom ready 事件没有任何关系。
18 //如果某些操作要确保在 dom ready 后执行,需要自己使用 jquery 等类库来保证
19 seajs.use(['jquery', 'page'], function($, page) {
20 $(function() {
21 page.init()
22 })
23 })
define
1 /*
2 CMD 模块定义 define(factory);
3 define 是全局函数,用来定义模块。
4 在开发时,define 仅接收一个 factory 参数。
5 factory 可以是一个函数,也可以是对象、字符串等类型。
6 factory 为对象、字符串等非函数类型时,表示模块的接口就是该对象、字符串等值。
7 factory 为函数时,表示模块的构造方法。执行该方法,可以得到模块向外提供的接口。
8 */
9 define(function(require, exports, module) {
10
11 // The module code goes here
12
13 });
14
15 /*
16 模块代码需要用 define 回调包起来:id 与 dependencies 参数是可以省略的
17 id 用来显式指定模块 ID。当你的项目上线,所有的模块都合并到了一个文件中,如果不显示指定, SeaJS 就无从知道哪个模块是哪个了。在开发的时候,一般用不到它。
18 dependencies 也是如此。它列出了当前模块所依赖的模块,在开发的时候是不需要写明的。 SeaJS 会检查你的模块回调函数,找到所有的 require 语句,从而得到你的模块的所有依赖。 在真正 require 当前模块时,会先去请求这个模块的依赖,加载完毕,再去初始化当前的模块。
19 */
20 define(id, dependencies, function(require, exports, module) {
21 // module code.
22 });
require
1 /*
2 require 是一个方法,用来获取其他模块提供的接口。
3 require 接受 模块标识 作为唯一参数
4
5 模块依赖解析,靠的是三个重要的规则:
6 不能重命名 require
7 不能覆盖 require
8 require 的参数必须是字符串字面量,不可以 require(foo()) 或者 require(bar), 也不可以是 require(should_be_a ? 'a' : 'b')。 参数值必须是字符串直接量,如 require("my-module");
9 核心原因是因为在浏览器端,文件的读取是异步的,依赖信息要提前获取,不能在运行时才确定。在服务器端,文件读取是同步的,因此可以是变量。
10 */
11 define(function(require) {
12 var a = require('./a');
13 a.doSomething();
14 });
require.async
1 /*
2 require.async(id, callback)
3 async 方法可用来异步加载模块,并在加载完成后执行指定回调。
4 */
5 define(function(require, exports, module) {
6 // load one module
7 require.async('./b', function(b) {
8 b.doSomething();
9 });
10
11 // load multiple modules
12 require.async(['./c', './d'], function(c, d) {
13 // do something
14 });
15 });
require.resolve
1 /*
2 require.resolve(id)
3 使用模块系统内部的路径解析机制来解析并返回模块路径。该函数不会加载模块,只返回解析后的绝对路径。
4 */
5 define(function(require, exports) {
6 console.log(require.resolve('./b'));
7 // ==> 'http://example.com/js/b.js'
8 });
exports
1 /*
2 exports 是一个对象,用来向外提供模块接口。
3 exports 仅仅是 module.exports 的一个引用。
4 在 factory 内部给 exports 重新赋值时,并不会改变 module.exports 的值。
5 因此给 exports 赋值是无效的,不能用来更改模块接口,正确的写法是用 return 或者给 module.exports 赋值。
6 exports = {}是错误的,module.exports ={}才是正确的写法。
7 */
8
9 define(function(require, exports) {
10 // snip...
11 exports.foo = 'bar';
12 exports.doSomething = function() {};
13 });
14 module.exports
15
16 define(function(require, exports, module) {
17 // snip...
18 module.exports = {
19 name: 'a',
20 doSomething: function() {};
21 };
22 });
module
1 *
2 module 是一个对象,上面存储了与当前模块相关联的一些属性和方法。
3 */
4 define(function(require, exports, module) {
5
6 //module.id 模块标识。require(module.id) 必然返回此模块的 exports 。
7 console.log(require(module.id) === exports); // true
8
9 //module.uri根据模块系统的路径解析规则得到的模块绝对路径。
10 console.log(module.uri); // http://example.com/path/to/this/file.js
11
12 //module.dependencies dependencies 是一个数组,表示当前模块的依赖列表。
13
14 /*
15 module.exports 当前模块对外提供的接口。
16 module.exports 的赋值需要同步执行,不能放在回调函数里
17 */
18 });
以上接口是最常用的,要牢记于心。
可写成如下
1 seajs.config({
2 alias: {
3 'jquery': 'http://modules.seajs.org/jquery/1.7.2/jquery.js'
4 }
5 });
6
7 define('hi', function(require, exports) {
8 exports.sayHi = function() {
9 alert('hi')
10 }
11 })
12
13 seajs.use(['jquery', 'hi'], function($, h) {
14 $('#beautiful-sea').click(h.sayHi)
15 });
模块化后的js写法
1 define(function(require, exports, module) = {
2
3 //原jquery.js代码...
4
5 module.exports = $.noConflict(true);
6 });
7
8 //init.js
9 define(function(require, exports, module) = {
10 var $ = require('jquery');
11 var m1 = require('module1');
12
13 exports.initPage = function() {
14 $('.content').html(m1.run());
15 }
16 });
17
18 //module1.js
19 define(function(require, exports, module) = {
20 var $ = require('jquery');
21 var m2 = require('module2');
22 var m3 = require('module3');
23
24 exports.run = function() {
25 return $.merge(['module1'], $.merge(m2.run(), m3.run()));
26 }
27 });
28
29 //module2.js
30 define(function(require, exports, module) = {
31 exports.run = function() {
32 return ['module2'];
33 }
34 });
35
36 //module3.js
37 define(function(require, exports, module) = {
38 var $ = require('jquery');
39 var m4 = require('module4');
40
41 exports.run = function() {
42 return $.merge(['module3'], m4.run());
43 }
44 });
45
46 //module4.js
47 define(function(require, exports, module) = {
48 exports.run = function() {
49 return ['module4'];
50 }
51 });
实际使用中
在工程内使用seajs,以前引用的插件、模块也都要用define的语法重新进行封装,比较麻烦,老代码可以不修改,继续使用就好。但强烈建立花点时间都修改成 CMD 模块,这样对以后的维护,以及页面性能很有好处。不然以后修改起来估计会更麻烦。
其实可以混用的,比如:
1 <script src="jquery.js"></script>
2 <script src="underscore.js"></script>
3 <script src="backbone.js"></script>
4
5 <script src="sea.js"></script>
这样,常用的 jquery 等类库,依旧是传统的用法,用全局变量引用就好,通过同步引入的方式,也不会有依赖顺序问题。 自己的代码,都按照 CMD 规范写成模块的形式。
其实上面的方式挺好的,特别对于要兼容老代码的情况的。 推荐还是都彻底模块化,看起来要多写一些 require,但值得,因为这样可以让每个模块自身的信息完整,从而减少对 环境的依赖,对后续的可维护性很好益处。
seajs官方api
第三方库
SeaJS 提供了一个类似于npm的管理工具,里面有他们改造好的第三方库,你可以在这里找找是否有适合的:
seajs blog 等文档
初级入门
中级使用
高级探索
http://www.heiniuhaha.com/seajs/2012/08/13/seajs-cheet-sheet/ 转
七、实例
1 // 页面调用
2 <script src="js/sea.js"></script>
3 <script>
4 seajs.use('init', function(a){
5
6 // a是init模块的外部接口,等init加载完就会将
7 a.init();
8
9 });
10 </script>
11
12
13 // init.js
14 // 基本配置
15 seajs.config({
16 alias: {
17 'jquery': 'jquery.min.js',
18 'transition': 'animate'
19 }
20 });
21
22 define(function(require, exports, module){
23
24 var an = require("transition");
25 require("jquery"); // 注意加载jquery只需要加载,不能赋值给一个变量来调取
26
27 function init(){
28 alert("aa");
29 }
30
31 $("#moveBtn").click(function(){
32 an.moveBox($(".box"));
33 })
34
35 exports.init = init;
36 })
37
38
39 // animate.js
40 define(function(require, exports, module){
41
42 // 模块外部接口
43 exports.moveBox = function(boxId){
44 boxId.stop().animate({left: "1000px"}, 5000);
45 }
46
47 // 模块接口,也将暴露给全局
48 window.moveBox = exports.moveBox = function(boxId){
49 boxId.stop().animate({left: "1000px"}, 5000);
50 }
51
52 })
二、API 快速参考
一、seajs.config
用来对 Sea.js 进行配置。
二、seajs.use
用来在页面中加载一个或多个模块。
三、define
用来定义模块。Sea.js 推崇一个模块一个文件,遵循统一的写法:
require
,exports
和module
三个参数可酌情省略,具体用法如下。四、require
require
用来获取指定模块的接口。注意,
require
只接受字符串直接量作为参数五、require.async
用来在模块内部异步加载一个或多个模块。
六、exports
用来在模块内部对外提供接口。
七、module.exports
与
exports
类似,用来在模块内部对外提供接口。module.exports
与exports
的区别以上 7 个接口是最常用的,要牢记于心。
---------------------------------------------------------------------------------------------------------------------------------------
四、seajs模块依赖的加载处理
最近在做项目的时候发现一些关于模块依赖问题,特记录下:
比如现有3个文件:
比如执行init.js时,init.js、jquery.plugA.js、jquery.plugB.js都会依赖到jquery,那么这种情况下seajs对jquery如何处理的呢?只执行一次?执行多次?还是其他方式?
此处参考玉伯的回答:
模块调用,比如:
var a = require('./a')
在执行 require(‘./a’) 时,会获取模块的接口,如果是第一次调用,会初始化模块 a,以后再调用时,直接返回模块 a 的接口 define 只是注册模块信息,比如打包之后:define(id, deps, factory)
是注册了一个模块到 seajs.cache 中,define 类似:seajs.cache[id] = { id: id, dependencies: deps, factory: factory }
五、seajs实战参考
该页面列举了 SeaJS 中的常用实战过程中的问题。只要掌握这些方法,就可以娴熟地开始对你的网站进行模块化开发了。
默认情况下,SeaJS 要求所有文件都是标准的 CMD 模块,但现实场景下,有大量 jQuery 插件等非 CMD 模块存在。在 SeaJS 里,通过以下方式,可以直接调用非标准模块。
全站通用的要加载的库只写一次,而不想每个js里都调用,太繁琐
1. 暴露 jQuery
jQuery 插件都依赖 jQuery 模块,为了加载 jQuery 插件,首先得将 jQuery 模块暴露出来:
2. 修改 jQuery 插件的接口
我们以 jquery.cookie 插件为例。
3. 调用 Cookie 插件
这样,在其他模块中,就可以直接调用 cookie 插件了:
seajs里版本号和时间戳问题
用 seajs 组织项目,上线后,经常需要更新特定文件或所有文件的时间戳,以清空浏览器缓存。最简单的方式是:
条件加载
第一种:把依赖的模块都在 define 头部手工声明,不再依赖 SeaJS 的自动解析功能。这个模块同时依赖 play 和 work 两个模块,加载器会把这两个模块文件都下载下来。如果需要在 require 模块之后串行执行代码,那么只能用这个方式。
第二种:使用 require.async 来进行条件加载,从静态分析的角度来看,require.async适合需要执行动态加载的模块很大(比如大量 json 数据),不适合都下载下来。但是require.async 方式加载的模块,不能打包工具找到,自然也不能被打包进上线的 js 中;而前一种方式可以。
按需加载
很多时候模块并不需要立即加载,等到需要时再加载,性能更好。
六、seajs快速参考
该页面列举了 SeaJS 中的常用 API。只要掌握这些方法,就可以娴熟地进行模块化开发。
启动模块系统
seajs.config
seajs.use
define
require
require.async
require.resolve
exports
module
以上接口是最常用的,要牢记于心。
可写成如下
模块化后的js写法
实际使用中
在工程内使用seajs,以前引用的插件、模块也都要用define的语法重新进行封装,比较麻烦,老代码可以不修改,继续使用就好。但强烈建立花点时间都修改成 CMD 模块,这样对以后的维护,以及页面性能很有好处。不然以后修改起来估计会更麻烦。
其实可以混用的,比如:
这样,常用的 jquery 等类库,依旧是传统的用法,用全局变量引用就好,通过同步引入的方式,也不会有依赖顺序问题。 自己的代码,都按照 CMD 规范写成模块的形式。
其实上面的方式挺好的,特别对于要兼容老代码的情况的。 推荐还是都彻底模块化,看起来要多写一些 require,但值得,因为这样可以让每个模块自身的信息完整,从而减少对 环境的依赖,对后续的可维护性很好益处。
seajs官方api
第三方库
SeaJS 提供了一个类似于npm的管理工具,里面有他们改造好的第三方库,你可以在这里找找是否有适合的:
seajs blog 等文档
初级入门
中级使用
高级探索
http://www.heiniuhaha.com/seajs/2012/08/13/seajs-cheet-sheet/ 转
七、实例