Sea.js框架构建

CMD模块定义规范

在Sea.js中,所有JavaScript模块都遵循CMD(Common Module Definition)模块定义规范。该规范明确了模块的基本书写
格式和基本交互规则。在CMD规范中,一个模块就是一个文件。

代码的书写格式为:define(factory);

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
   });

factory函数的参数之require

1.require是factory函数的第一个参数,它是一个方法,接受模块标识作为唯一参数,用来获取其他模块提供的接口。用法如下:

define(function(require, exports, module){
   // 获取模块a的接口
   var a = require('a');
   // 调用模块a的方法
   a.doSomething();
});

2.require.async方法用来在模块内部异步加载模块,并在加载完成后执行指定回调。callback 参数可选。

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一般用来加载可延迟异步加载的模块。

require书写规范

1.模块factory构造方法的第一个参数必须命名为require。

// 错误!
define(function(req) {
  // code
});
// 正确!
define(function(require) {
  // code
});

2.不要重命名require函数,或在任何作用域中给require重新赋值。

// 错误!
define(function(req) {
  // code
});
// 正确!
define(function(require) {
  // code
});

3.require的参数值必须是字符串直接量。

// 错误!
require(myModule);
// 错误!
require("my-" + "module");
// 错误!
require("MY-MODULE".toLowerCase());
// 正确!
require("my-module");

factory函数的参数之exports

exports是一个对象,用来向外提供模块接口。

define(function(require, exports) {
   // 对外提供foo属性
   exports.foo = 'bar';
   // 对外提供doSomething方法
   exports.doSomething = function(){};
});

注意:exports仅仅是module.exports的一个引用。在factory内部给exports重新赋值时,并不会改变module.exports的值。因此给exports赋值是无效的,不能用来更改模块接口。

factory函数的参数之module

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的赋值需要同步执行,不能放在回调函数里。

CMD规范执行流程

模块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 $

sea.js框架构建

sea.js的引入

在调用seajs.use之前,需要先引入sea.js文件,可直接使用script标签同步引入:

<script type="text/javascript" src="http://localhost/tseajs/static/js/seajs/sea-debug.js">
</script>

seajs配置说明

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>

sea.js模块的引入

seajs.use: public API,可在全局任何位置调用该方法
<script type="text/javascript">
 seajs.use('modules/base', function(base) {
    base.script_load('index');
  });
</script>

文件后缀的自动添加规则

Sea.js在解析模块标识时,除非在路径中有问号(?)或最后一个字符是井号(#),否则都会自动添加JS扩展名(.js)。如果不想
自动添加扩展名,可以在路径末尾加上井号(#)。

JQ插件模块化

JQ模块化

如果想要将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插件模块化

如果想要将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>

案例分享

案例结构如图: Seajs案例结构.jpg

配置sea-config

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

加载JQ插件

定义应用模块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

转载于:https://my.oschina.net/u/1757002/blog/868538

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值