base配置:
seajs.config({ base:"http://localhost:8080/sealJs/"}note: 这里是设置基础的文件夹,所有路径都是相对于他来说的
alias: { 'jquery1': 'moduler1/fakeJquery',/*相对地址,相对于base来说的,表示http://localhost:8080/sealJs/moduler1/fakeJquery.js可以用require('jquery1')完成*/ 'diralias':"http://localhost:8080/sealJs/moduler1/directalias.js"/*如果是直接地址表示的别名,那么不是相对于base来说的,而是绝对路径*/ }note:如果是相对地址就是相对于base路径来说的。
paths: { 'm1':'moduler1', /*paths表示当要分文件夹管理,或者文件的目录很深的时候用的方式,路径也是相对于base来说的 所以:m1表示http://localhost:8080/sealJs/moduler1/,a.js就是m1/a m3表示http://localhost:8080/sealJs/moduler3/,a.js就是m3/a */ 'm3':'moduler3', 'lug':"language" }note: 当路径嵌套很深的时候我们用paths来配置,或者要分文件夹管理的时候可以用这种方式,也是相对于base来说的。
vars: /*如果模块路径在运行时候才能确定,那么我们就用vars来配置*/ { 'locale':"zh-cn" }note:这当我们要改成英文文件的时候就只要在这里修改就可以了,特别有利于动态的加载过程。调用方式如下:
//下面我们调用通过vars来指定的动态路径下面的文件,这种方式可以有利于多个模块之间的动态切换 var lg=require("lug/{locale}.js"); lg.sayLanguage();charset配置:
/*指定加载link或者script标签时候的编码方式*,可以是字符串也可以是一个函数*/ charset:function(url) { if(url.indexOf("http://localhost:8080/sealJs/xxx")===0) { return 'gbk';/*xxx目录下的文件用gbk编码*/ } return "utf-8"; /*其它用UTF-8*/ }map配置:
/*map用于对模块路径进行映射修改,可用于路径转换,在线调试等 map:[ [".js","-debug.js"] ] 这种映射方式将会使得所有的.js变成后缀为-debug.js的文件,下面这种映射将会使得对zh-cn.js的访问变成对zh-cn1.js的访问 map:[ ["http://localhost:8080/sealJs/language/zh-cn.js","http://localhost:8080/sealJs/language/zh-cn1.js"] ] */debug配置:
debug:true/*值为true时候,加载器不会删除动态插入的script标签,插件可以通过debug来决定log的输出信息*/use方法:
/*调用具体的模块,调用格式为seajs.use(id, callback?),其中回调可以省略,也可以同时加载多个模块(第一个参数是数组),这时候回调函数的参数的顺序就是前面加载的 模块的顺序,类似于Deferred对象的参数顺序!调用方式为: seajs.use("moduler2/moduler2.js"); seajs.use和domReady没有任何关系,如果要保证domready后才执行特定的逻辑,用jquery来保证。不过要加载jquery首先要jquery自己完成模块化 我用的jquery-1.11.3修改其中的代码if ( typeof define === "function" && define.amd )为if ( typeof define === "function")就可以了! 我这时候把jquery放在工程根目录下面: */ seajs.use(["jquery","moduler2/moduler2"],function($,main) { $(document).ready(function() { //如果要在domReady事件后执行相应的逻辑,我们就放在这个方法里面! //注意:use方法第一个参数一定要有,但是可以是null或者一个变量! main.init(); });注意:我用的是 jquery.1-11.3,所以要把下面的代码进行修改:
if ( typeof define === "function" && define.amd ) { define( "jquery", [], function() { return jQuery; }); }修改为:
if ( typeof define === "function" ) { define( "jquery", [], function() { return jQuery; }); }note:很显然,这时候的就query就自己进行了模块化了,其中id就是jquery字符串。 这时候我把jquery.js放在了根目录了,当然也可以自己配置。
如果要知道模块信息可以通过在chorome浏览器中console中输入:seajs.cache就可以看到!可以查阅当前模块系统中所有模块的信息,他遵守CMD规范,满足一个文件就是一个模块。
resolve配置:
//用seajs.resolve对传入的字符串进行路径解析 var result=seajs.resolve('jquery1'); console.log(result);note:这时候可以通过resolve把传入的字符串解析为 路径信息。如会把上面的jquery1解析为:http://localhost:8080/sealJs/moduler1/fakeJquery.js也就是表示具体的路径。
调用方式为:define define(id?, deps?, factory)
字符串 id
表示模块标识,数组 deps
是模块依赖。id
和 deps
参数可以省略。省略时,可以通过构建工具自动生成。注意:带 id
和 deps
参数的 define
用法不属于 CMD 规范,而属于 Modules/Transport 规范。
define.cmd:
一个空对象,可用来判定当前页面是否有 CMD 模块加载器:
if (typeof define === "function" && define.cmd) {//从上面的jquery源码中jquery判断了define.amd,而不是define.cmd!
// 有 Sea.js 等 CMD 模块加载器存在
}
参数1:require参数
该参数是模块标识符,如上面通过paths配置或者alias配置的键名都是模块标识符,如果define的时候没有模块标识符,那么就是该文件的地址。
参数2:exports对象
exports
是一个对象,用来向外提供模块接口。
define(function(require, exports) {
// 对外提供 foo 属性
exports.foo = 'bar';
// 对外提供 doSomething 方法
exports.doSomething = function() {};
});
exports
仅仅是 module.exports
的一个引用。在 factory
内部给 exports
重新赋值时,并不会改变 module.exports
的值。因此给 exports
赋值是无效的,不能用来更改模块接口。exports表示向外提供的接口,是一个object对象,只有在exports中的方法外部能访问,内部的变量都是私有的变量,外部无法访问。提供外部接口的方法有三种,第一种就是直接绑定在exports对象上面;第二种就是直接返回一个对象;第三种方法,如果return是内部唯一的代码,那么可以直接define({json对象})!如下:
define(function(require, exports, module) { // 直接绑定到module的exports对象上面! module.exports = { foo: 'bar', doSomething: function() {} }; });
如果我们需要返回的暴露的对象是一个特定的类型,那么我们就可以通过重置exports对象:
seajs配置为:
seajs.config({ base:"http://localhost:8080/sealJs/" }); seajs.use("add2allmoduler/extend"); seajs.use("add2allmoduler/a");extend.js模块为:
define(function(require, exports, module) { function someClass(){ this.name="qinliang"; this.sex="male"; } //exports已经是被重置了,也就是这时候的exports就是someClass类型的对象 //同时可以通过 module.exports为这个新的exports对象添加新的属性和方法 module.exports = new someClass(); module.exports.sayName=function() { return "qinliang sayName"; } });a.js模块(用于调用extend模块的代码)
define(function(require, exports, module) { var exports=require("add2allmoduler/extend"); //获取到extend模块暴露出来的公有的属性! console.log(exports.name); //获取到extend模块暴露出来的共有方法 console.log(exports.sayName()); });
参数3:module
具有id,url,dependencies,exports属性(Array类型)打开图表查看(从该图中可以看出dependencies是5,因为moduler2.js是整个工程的main函数),其中id就是define函数的第一个参数,url根据模块系统的路径解析规则得到的模块绝对路径。dependencies
是一个数组,表示当前模块的依赖。一般情况下(没有在 define
中手写 id
参数时),module.id
的值就是 module.uri
,两者完全相同。传给 factory
构造方法的 exports
参数是 module.exports
对象的一个引用。只通过 exports
参数来提供接口,有时无法满足开发者的所有需求。 比如当模块的接口是某个类的实例时,需要通过 module.exports
来实现,j见上例:
define(function(require, exports, module) { // exports 是 module.exports 的一个引用 console.log(module.exports === exports); // true // 重新给 module.exports 赋值 module.exports = new SomeClass(); // exports 不再等于 module.exports console.log(module.exports === exports); // false });注意:对module.exports赋值需要同步执行,不能放在 回调函数里面
当我们需要为所有的模块都添加一个共同的方法的时候,我们就可以用moduler的constructor属性:
在主页中我们调用了extend.js和a.js代码如下:
seajs.config({ base:"http://localhost:8080/sealJs/" }); seajs.use("add2allmoduler/extend"); seajs.use("add2allmoduler/a");extend.js中代码如下:
define(function(require, exports, module) { //当需要添加一个方法或者属性到所有的模块中,我们就需要用到module.constructor属性! var Module = module.constructor; //打印为module的构造函数function t(a,b){this.uri=a,this.dependencies=b||[],this.deps={},this.status=0,this._entry=[]} //console.log(Module); Module.prototype.filename = function() { var id = this.id; //调用filename是a.js,所以这里的id为:http://localhost:8080/sealJs/add2allmoduler/a.js // console.log("id="+id); var parts = id.split('/'); //返回文件名 return parts[parts.length - 1]; }; });note:在extend中我们通过获取到 module的constructor属性,然后为其prototype中添加一个共同的函数,那么在其它页面中如a.js中就可以通过module访问这个共有的方法:
define(function(require, exports, module) { //filename方法就是通过前面的moduler的constructor属性添加的方法,也会封装到该define方法具有的module参数上。调用filename的this就是这个module! //console.log(module.filename); exports.filename = module.filename(); });
有时候,我们需要给所有 require
参数对象添加一些公用属性或方法。这时, 使用 require.constructor
来实现会非常方便。
seajs.config({ base:"http://localhost:8080/sealJs/" }); seajs.use("add2allmoduler/extend"); seajs.use("add2allmoduler/a");extend.js代码:
define(function(require, exports, module) { //打印:Function() { [native code] } //console.log(require.constructor); var requireC=require.constructor; //为所有的require对象添加一个方法filename方法 requireC.prototype.filename=function() { return "filename"; } requireC.prototype.name="qinlaing"; });a.js源码:
define(function(require, exports, module) { var filename=require.filename(); //调用函数 console.log(filename); //绑定到require上面的属性,通过constructor绑定的! console.log(require.name); });note:我们看到,上面的 filename,name都通过了require的constructor属性, 结合prototype 实现了属性和方法的共享。
require.async函数:调用格式require.async(id,callback?)
require.async
方法用来在模块内部异步加载模块,并在加载完成后执行指定回调。callback
参数可选。
define(function(require, exports, module) {
// 异步加载一个模块,在加载完成时,执行回调
require.async('./b', function(b) {
b.doSomething();
});
// 异步加载多个模块,在加载完成时,执行回调
require.async(['./c', './d'], function(c, d) {
c.doSomething();
d.doSomething();
});
});
seajs.data属性:
通过 seajs.data,可以查看 seajs 所有配置以及一些内部变量的值,可用于插件开发。当加载遇到问题时,也可用于调试。控制台输入seajs.data可以获取到所有的配置信息。
seajs.log方法:
log方法默认不会显示,当seajs.debug为true时候才会显示。该方法用于log插件的开发。这时候需要在页面引入seajs.log.js!
preload配置项:
用于在普通模块加载前加载指定的模块。其中空字符串会被忽略。注意:preload
中的配置,需要等到 use 时才加载。但是会保证在use中的模块加载之前,preload中的模块已经加载完成。
// 在老浏览器中,提前加载好 ES5 和 json 模块 seajs.config({ preload: [ Function.prototype.bind ? '' : 'es5-safe', this.JSON ? '' : 'json' ] });注意:preload配置不能放在模块文件里面。
seajs.config({ preload: 'a' }); define(function(require, exports) { // 此处执行时,不能保证模块 a 已经加载并执行好 });下面我们学习一下几个常见的插件:
<script src="seajs-style.js"></script>//引入插件 seajs.importStyle("body { background-color: red; }")//执行importStyle方法就会通过构建一个style标签插入到页面中。第二个参数是id,用于指定style的id属性。note:这种方式插入时候需要对\0等转义为\\0;在IE下style不能超过31个,否则seajs会抛出异常。详见 importStyle官方文档
通过下面的步骤来完成使用
<script src="seajs-css.js"></script> seajs.use("css/style.css")note:这个插件和link标签一样,用于加载一个css文件。
<script src="seajs-preload.js"></script> seajs.config({ preload: ['jquery'] }) seajs.use("path/to/mod");//preload中的模块会等到use调用的时候才会加载,但是会在path/to/mod模块加载之前完成,基于seajs2.3.0!(4) flush和combo插件的使用
<script src="path/to/sea.js"></script> <script src="path/to/seajs-combo.js"></script> <script src="path/to/seajs-flush.js"></script> <script> seajs.use(['a', 'b'], function(a, b) { // ... }) seajs.use(['c', 'd'], function(c, d) { // ... }) // The combined request is http://test.com/path/to/??a.js,b.js,c.js,d.js seajs.flush() </script>note:这种方式可以将所有的http请求一次性发送出去。
<script src="path/to/sea.js"></script> <script src="path/to/seajs-log.js"></script> <script> seajs.log('hello world','warn')//警告信息 </script>注意:
console.log
信息默认不会显示,在 Sea.js 的 debug
为 true 时才显示。
<script src="path/to/sea.js"></script> <script src="path/to/seajs-text.js"></script> <script> define("main", function(require) { // You can require `.tpl` file directly var tpl = require("./data.tpl") }) </script>note:该插件用于加载json,tpl,html后缀等文件
Sea.js 通过 XHR 来加载文本文件。受同源策略限制,在开发完成后,推荐通过构建工具将文本文件转换为 JS 代码。这样,上线后就可以从任意域加载。
Sea.js 原生支持 css 文件的加载,直接 require('path/to/file.css')
即可
(7)health插件的使用
<script src="path/to/sea.js"></script> <script src="path/to/seajs-health.js"></script> <script> // You can use seajs.health method to collecting health data. var healthData = seajs.health() </script>note: health插件用于检测CMD的模块的健康状况。
seajs.config({ "alias": { "seajs-debug": "path/to/seajs-debug" } })然后在URL中加入?seajs-debug,并且重新加载页面
总结:
如果说jQuery找不到,那么就要按照上面修改jQuery源码相关部分;同时这种动态加载的方式会在缓存中,即使用Ctr+F5刷新也会读取缓存,除非手动清除缓存;掌握module.constructor.prototype和require.constructor.prototype,module.exports实现数据共享!
有时候为了保证DOM加载完成从而进行业务逻辑的处理,可以用jQuery保证DOM加载完全:
seajs.use(["jquery"],function($) { $(document).ready(function() { $('input').click(function() { seajs.use(['hello'],function(hello) { hello.sayHello(); }); }) });