在Sea.js中,全部JavaScript模块都遵循CMD(Common Module Definition)模块定义规范。该规范明确了模块的基本书写 格式和基本交互规则。在CMD规范中,一个模块就是一个文件。
代码的书写格式为:define(factory);javascript
define是一个全局函数,用来定义模块。参数factory,能够是一个函数,也能够是一个对象或字符串。当factory为对象、 字符串时,表示模块的接口就是该对象、字符串。以下: 1>.能够定义一个JSON数据模块:define({ "foo": "bar" }); 2>.也能够定义一个字符串模块:define('My name is Hm.'); 3>.当factory为函数时,表示是模块的构造方法。执行该构造方法,能够获得模块向外提供的接口。 factory方法在执行时,默认会传入三个参数:require、exports 和 module,以下: define(function(require, exports, module) { //code });
1.require是factory函数的第一个参数,它是一个方法,接受模块标识做为惟一参数,用来获取其余模块提供的接口。用法以下:php
define(function(require, exports, module){ // 获取模块a的接口 var a = require('a'); // 调用模块a的方法 a.doSomething(); });
2.require.async方法用来在模块内部异步加载模块,并在加载完成后执行指定回调。callback 参数可选。css
define(function(require, exports, module) { // 异步加载b模块,在加载完成时,执行回调 require.async('b', function(b) { b.doSomething(); }); // 异步加载多个模块,在加载完成时,执行回调 require.async(['c', 'd'], function(c, d) { c.doSomething(); d.doSomething(); }); });
注意:require是同步往下执行,require.async则是异步回调执行。require.async通常用来加载可延迟异步加载的模块。html
1.模块factory构造方法的第一个参数必须命名为require。java
// 错误! define(function(req) { // code }); // 正确! define(function(require) { // code });
2.不要重命名require函数,或在任何做用域中给require从新赋值。jquery
// 错误! define(function(req) { // code }); // 正确! define(function(require) { // code });
3.require的参数值必须是字符串直接量。web
// 错误! require(myModule); // 错误! require("my-" + "module"); // 错误! require("MY-MODULE".toLowerCase()); // 正确! require("my-module");
exports是一个对象,用来向外提供模块接口。正则表达式
define(function(require, exports) { // 对外提供foo属性 exports.foo = 'bar'; // 对外提供doSomething方法 exports.doSomething = function(){}; });
注意:exports仅仅是module.exports的一个引用。在factory内部给exports从新赋值时,并不会改变module.exports的值。所以给exports赋值是无效的,不能用来更改模块接口。json
module是一个对象,上面存储了与当前模块相关联的一些属性和方法。 1>.module.id:模块的惟一标识。 2>.module.uri:根据模块系统的路径解析规则获得的模块绝对路径。 3>.module.dependencies:是一个数组,表示当前模块的依赖。 4>.module.exports:当前模块对外提供的接口。
传给factory构造方法的exports参数是module.exports对象的一个引用。只经过exports参数来提供接口,有时没法知足开发者的全部需求。好比当模块的接口是某个类的实例时,须要经过module.exports来实现:数组
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的赋值须要同步执行,不能放在回调函数里。
模块a.js:
define(function(require,exports,modules){ var $ = require('jquery') }) 1>.经过回调函数的Function.toString函数,使用正则表达式来捕捉内部的require字段,找到require('jquery')内部依赖的 模块jquery 2>.根据配置文件,找到jquery的js文件的实际路径 3>.在dom中插入script标签,载入模块指定的js,绑定加载完成的事件,使得加载完成后将js文件绑定到require模块指定的id (这里就是jquery这个字符串)上 4>.回调函数内部依赖的js所有加载(暂不调用)完后,调用回调函数 5>.当回调函数调用require('jquery'),即执行绑定在'jquery'这个id上的js文件,即刻执行,并将返回值传给var $
在调用seajs.use以前,须要先引入sea.js文件,可直接使用script标签同步引入:
<script type="text/javascript" src="http://localhost/tseajs/static/js/seajs/sea-debug.js"> </script>
seajs.config支持的属性有:
'alias' : (当模块标识很长时,可使用alias来简化,使用alias可让文件的真实路径与调用标识分开,有利于统一维护。) 'paths' : (当目录比较深,或须要跨目录调用模块时,可使用paths来简化书写,paths配置也能够结合alias配置一块儿使用, 让模块引用很是方便。) 'vars' : (有些场景下,模块路径在运行时才能肯定,这时可使用vars 变量来配置,vars配置的是模块标识中的变量值,在 模块标识中用{key}来表示变量。) 'map' : (该配置可对模块路径进行映射修改,可用于路径转换、在线调试等。) 'preload' : (使用preload配置项,能够在普通模块加载前,提早加载并初始化好指定模块。preload中的空字符串会被忽略掉。) 'debug' : (值为true时,加载器不会删除动态插入的script标签。插件也能够根据debug配置,来决策log等信息的输出。) 'base' : (Sea.js在解析模块路径标识时,会基于base路径来解析。) 'charset' : (获取模块文件时,<script>或<link>标签的charset属性。 默认是utf-8)
seajs.config经常使用配置项的配置示例:
seajs.config({ // 别名配置 alias: { 'jquery': 'libs/jquery/jquery.js', 'jquery.validate': 'libs/jquery.validate/jquery.validate.js' }, // 路径配置 paths: { 'gallery': 'https://a.alipayobjects.com/gallery' }, // 变量配置 vars: { 'locale': 'zh-cn' }, // 映射配置 map: [ ['http://example.com/js/app/', 'http://localhost/js/app/'] ], // 预加载项 preload: [ this.JSON ? '' : 'json' ], // 调试模式 debug: true, // Sea.js的基础路径 base: 'http://localhost/tseajs/static/js/', // 文件编码 charset: 'utf-8' });
seajs.config配置可直接使用script标签同步引入:
<script type="text/javascript" src="http://localhost/tseajs/static/js/seajs/sea-config.js"> </script>
seajs.use: public API,可在全局任何位置调用该方法 <script type="text/javascript"> seajs.use('modules/base', function(base) { base.script_load('index'); }); </script>
文件后缀的自动添加规则
Sea.js在解析模块标识时,除非在路径中有问号(?)或最后一个字符是井号(#),不然都会自动添加JS扩展名(.js)。若是不想 自动添加扩展名,能够在路径末尾加上井号(#)。
若是想要将JQ原始文件模块化在sea.js框架中使用,可在原始JQ文件中增长以下代码:
if ( typeof module === "object" && module && typeof module.exports === "object" ) { module.exports = jQuery; } else { window.jQuery = window.$ = jQuery; if ( typeof define === "function" ) { define( "jquery", [], function () { return jQuery; } ); } }
以下: /*! * jQuery JavaScript Library v1.9.1 * http://jquery.com/ */ (function( window, undefined ) { // jQ code if ( typeof module === "object" && module && typeof module.exports === "object" ) { module.exports = jQuery; } else { window.jQuery = window.$ = jQuery; if ( typeof define === "function" ) { define( "jquery", [], function () { return jQuery; } ); } } })( window );
如不想模块化JQ也能够直接使用script标签同步引入:
<script type="text/javascript" src="http://localhost/tseajs/static/js/libs/jquery/jquery.js"> </script>
若是想要将JQ插件模块化在sea.js框架中使用,可按照CMD规范将JQ插件定义为JQ插件模块:
以下: define(function (require, exports, module) { var jQuery = require("jquery");//插件若是依赖JQ时,要先引入JQ模块 //Plugin code return jQuery; });
如不想模块化JQ插件也能够直接使用script标签同步引入:
<script type="text/javascript" src="http://localhost/tseajs/static/js/libs/jquery.validate/jquery.validate.js"> </script>
sea-config.js文件的配置以下:
seajs.config({ // 别名配置 alias: { 'jquery': 'libs/jquery/jquery.js', 'jquery.validate': 'libs/jquery.validate/jquery.validate.js' }, // 变量配置 vars: { 'locale': 'zh-cn' }, // 调试模式 debug: true, // 基础路径 base: 'http://localhost/tseajs/static/js/', // 文件编码 charset: 'utf-8' });
定义主模块base.js文件,以下:
/** *项目主模块 */ define(function(require, exports, module) { //加载jquery, 并把$设为全局变量 window.$ = window.jQuery = $ = require('jquery'); //定义一个全局的模块加载函数.module为模块名,options为参数 exports.script_load = function(module, options) { //使用require.async异步加载模块。模块须要提供一个固定的对外调用接口,这里定义为run。 require.async('modules/' + module, function(module) { if (typeof(module.run) === 'function') { module.run(options); } }); }; });
定义应用模块index.js文件,以下:
define(function(require, exports, module) { var eventInit = function(){ $('#alert').click(function() { alert('test-4'); }); }; exports.run = function(){ //提供对外的调用接口run() $(function(){ alert('test-2'); alert('test-3'); }); $(alert('test-1')); eventInit() }; });
在app/index/index.html文件中使用定义的模块:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>sea.js应用</title> </head> <body> <button id="alert">点击我</button> </body> <script type="text/javascript" src="http://localhost/tseajs/static/js/seajs/sea-debug.js"></script> <script type="text/javascript" src="http://localhost/tseajs/static/js/seajs/sea-config.js"></script> <script type="text/javascript"> seajs.use('modules/base', function(base) {//启动主模块base.js base.script_load('index');//加载index.js }); </script> </html>
在浏览器中运行,在控制台中查看元素,经过模块加载器加载了jq文件,以下:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>sea.js应用</title> <script charset="utf-8" async="" src="http://localhost/tseajs/static/js/modules/base.js"></script>//加载了base.js模块 <script charset="utf-8" async="" src="http://localhost/tseajs/static/js/libs/jquery/jquery.js"></script>//加载了jquery.js模块 <script charset="utf-8" async="" src="http://localhost/tseajs/static/js/modules/index.js"></script>//加载了index.js模块 </head> <body> <button id="alert">点击我</button> <script type="text/javascript" src="http://localhost/tseajs/static/js/seajs/sea-debug.js"></script> <script type="text/javascript" src="http://localhost/tseajs/static/js/seajs/sea-config.js"></script> <script type="text/javascript"> seajs.use('modules/base', function(base) {//启动主模块base.js base.script_load('index');//加载index.js }); </script> </body> </html>
运行结果
运行文件后会依此弹出test-1,test-2,test-3,在点击按钮后会弹出test-4
定义应用模块login.js文件,以下:
define(function(require, exports, module) { require('jquery.validate');//引入模块化后的jq插件 var onReady = function() { $('form.login-form').validate({ debug: true, rules: { '[name=username]': { required: true }, '[name=password]': { required: true, rangelength:[3,10] } }, submitHandler: function(form) { alert("提交表单"); form.submit(); } }); }; exports.run = function() { $(onReady()); } });
在app/login/index.html文件中使用定义的模块:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>validator</title> <style type="text/css"> //样式定义 </style> </head> <body> <div id="form"> <form class="login-form" method="post" action=""> <input name="username" type="text" required><br /> <input name="password" type="password" required><br /> <button class="button" type="submit">登录</button> </form> </div> <script type="text/javascript" src="http://localhost/tseajs/static/js/seajs/sea-debug.js"></script> <script type="text/javascript" src="http://localhost/tseajs/static/js/seajs/sea-config.js"></script> <script type="text/javascript"> seajs.use('modules/base', function(base) {//启动主模块base.js base.script_load('login');//加载login.js }); </script> </body> </html>
在浏览器中运行,在控制台中查看元素,经过模块加载器加载了jq文件以及jq插件文件,以下:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>validator</title> <style type="text/css"> //样式定义 </style> <script charset="utf-8" async="" src="http://localhost/tseajs/static/js/modules/base.js"></script>//加载了base.js模块 <script charset="utf-8" async="" src="http://localhost/tseajs/static/js/libs/jquery/jquery.js"></script>//加载了jquery.js模块 <script charset="utf-8" async="" src="http://localhost/tseajs/static/js/modules/login.js"></script>//加载了login.js模块 <script charset="utf-8" async="" src="http://localhost/tseajs/static/js/libs/jquery.validate/jquery.validate.js"></script>//加载了jquery.validate.js模块 </head> <body> <div id="form"> <form class="login-form" method="post" action="" novalidate="novalidate"> <input name="username" type="text" required=""><br> <input name="password" type="password" required=""><br> <button class="button" type="submit">登录</button> </form> </div> <script type="text/javascript" src="http://localhost/tseajs/static/js/seajs/sea-debug.js"></script> <script type="text/javascript" src="http://localhost/tseajs/static/js/seajs/sea-config.js"></script> <script type="text/javascript"> seajs.use('modules/base', function(base) { base.script_load('login'); }); </script> </body> </html>
运行结果
运行案例,若输入框为空直接点击登录按钮会提示“This field is required.”;若在输入框中输入内容后再点击登录按钮则可 正常登录。
注意:由于jquery.validate.js插件依赖于jquery.js因此引入jquery.validate.js插件前须要先引入jquery.js,所以可在模块化jquery.validate.js插件时,先require("jquery")便可。可参考上面JQ插件模块化部分
Seajs 官网 http://seajs.org/docs
Seajs API文档 http://yslove.net/seajs
SeaJS中jQuery插件模块化及其调用方式 http://web322-szb.iteye.com/blog/1742930