seajs使用教程指南转载_第1页
seajs使用教程指南转载_第2页
seajs使用教程指南转载_第3页
seajs使用教程指南转载_第4页
seajs使用教程指南转载_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

seajs使用教程指南前言SeaJS是一个遵循CommonJS规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制。与jQuery等JavaScript框架不同,SeaJS不会扩展封装语言特性,而只是实现JavaScript的模块化及按模块加载。SeaJS的主要目的是令JavaScript开发模块化并可以轻松愉悦进行加载,将前端工程师从繁重的JavaScript文件及对象依赖处理中解放出来,可以专注于代码本身的逻辑。SeaJS可以与jQuery这类框架完美集成。使用SeaJS可以提高JavaScript代码的可读性和清晰度,解决目前JavaScript编程中普遍存在的依赖关系混乱和代码纠缠等问题,方便代码的编写和维护。SeaJS的作者是淘宝前端工程师玉伯。SeaJS本身遵循KISS(KeepItSimple,Stupid)理念进行开发,其本身仅有个位数的API,因此学习起来毫无压力。在学习SeaJS的过程中,处处能感受到KISS原则的精髓——仅做一件事,做好一件事。本文首先通过一个例子直观对比传统JavaScript编程和使用SeaJS的模块化JavaScript编程,然后详细讨论SeaJS的使用方法,最后给出一些与SeaJS相关的资料。前言传统模式vsSeaJS模块化

传统开发

SeaJS模块化开发使用SeaJS

下载及安装

SeaJS基本开发原则

模块的定义及编写

模块的载入及引用

SeaJS的全局配置

SeaJS如何与现有JS库配合使用

SeaJS项目打包部署一个完整的例子主要参考文献&SeaJS学习资源传统模式vsSeaJS模块化假设我们现在正在开发一个Web应用TinyApp,我们决定在TinyApp中使用jQuery框架。TinyApp的首页会用到module1.js,module1.js依赖module2.js和module3.js,同时module3.js依赖module4.js。使用传统的开发方法,各个js文件代码如下:?123456789101112131415161718192021222324252627//module1.jsvarmodule1={

run:function(){

return$.merge(['module1'],$.merge(module2.run(),module3.run()));

}}

//module2.jsvarmodule1={

run:function(){

return['module2'];

}}

//module3.jsvarmodule3={

run:function(){

return$.merge(['module3'],module4.run());

}}

//module4.jsvarmodule4={

run:function(){

return['module4'];

}}此时index.html需要引用module1.js及其所有下层依赖(注意顺序):?123456789101112131415161718<!DOCTYPEHTML><htmllang="zh-CN"><head>

<metacharset="UTF-8">

<title>TinyApp</title>

<scriptsrc="./jquery-min.js"></script>

<scriptsrc="./module4.js"></script>

<scriptsrc="./module2.js"></script>

<scriptsrc="./module3.js"></script>

<scriptsrc="./module1.js"></script></head><body>

<pclass="content"></p>

<script>

$('.content').html(module1.run());

</script></body></html>随着项目的进行,js文件会越来越多,依赖关系也会越来越复杂,使得js代码和html里的script列表往往变得难以维护。下面看看如何使用SeaJS实现相同的功能。首先是index.html:?12345678910111213141516<!DOCTYPEHTML><htmllang="zh-CN"><head>

<metacharset="UTF-8">

<title>TinyApp</title></head><body>

<pclass="content"></p>

<scriptsrc="./sea.js"></script>

<script>

seajs.use('./init',function(init){

init.initPage();

});

</script></body></html>可以看到html页面不再需要引入所有依赖的js文件,而只是引入一个sea.js,sea.js会处理所有依赖,加载相应的js文件,加载策略可以选择在渲染页面时一次性加载所有js文件,也可以按需加载(用到时才加载响应js),具体加载策略使用方法下文讨论。index.html加载了init模块,并使用此模块的initPage方法初始化页面数据,这里先不讨论代码细节。下面看一下模块化后JavaScript的写法:?12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152//jquery.jsdefine(function(require,exports,module)={

//原jquery.js代码...

module.exports=$.noConflict(true);});

//init.jsdefine(function(require,exports,module)={

var$=require('jquery');

varm1=require('module1');

exports.initPage=function(){

$('.content').html(m1.run());

}});

//module1.jsdefine(function(require,exports,module)={

var$=require('jquery');

varm2=require('module2');

varm3=require('module3');

exports.run=function(){

return$.merge(['module1'],$.merge(m2.run(),m3.run()));

}});

//module2.jsdefine(function(require,exports,module)={

exports.run=function(){

return['module2'];

}});

//module3.jsdefine(function(require,exports,module)={

var$=require('jquery');

varm4=require('module4');

exports.run=function(){

return$.merge(['module3'],m4.run());

}});

//module4.jsdefine(function(require,exports,module)={

exports.run=function(){

return['module4'];

}});乍看之下代码似乎变多变复杂了,这是因为这个例子太简单,如果是大型项目,SeaJS代码的优势就会显现出来。不过从这里我们还是能窥探到一些SeaJS的特性:一是html页面不用再维护冗长的script标签列表,只要引入一个sea.js即可。二是js代码以模块进行组织,各个模块通过require引入自己依赖的模块,代码清晰明了。通过这个例子朋友们应该对SeaJS有了一个直观的印象,下面本文具体讨论SeaJS的使用。使用SeaJS要在项目中使用SeaJS,你所有需要做的准备工作就是下载sea.js然后放到你项目的某个位置。SeaJS项目目前托管在GitHub上,主页为\o"/seajs/seajs/"/seajs/seajs/。可以到其git库的build目录下(\o"/seajs/seajs/tree/master/build"/seajs/seajs/tree/master/build)下载sea.js(已压缩)或sea-debug.js(未压缩)。下载完成后放到项目的相应位置,然后在页面中通过<script>标签引入,你就可以使用SeaJS了。在讨论SeaJS的具体使用前,先介绍一下SeaJS的模块化理念和开发原则。使用SeaJS开发JavaScript的基本原则就是:一切皆为模块。引入SeaJS后,编写JavaScript代码就变成了编写一个又一个模块,SeaJS中模块的概念有点类似于面向对象中的类——模块可以拥有数据和方法,数据和方法可以定义为公共或私有,公共数据和方法可以供别的模块调用。另外,每个模块应该都定义在一个单独js文件中,即一个对应一个模块。下面介绍模块的编写和调用。模块定义函数defineSeaJS中使用“define”函数定义一个模块。因为SeaJS的文档并没有关于define的完整参考,所以我阅读了SeaJS源代码,发现define可以接收三个参数:?123456789/***Definesamodule.*@param{string=}idThemoduleid.*@param{Array.|string=}depsThemoduledependencies.*@param{function()|Object}factoryThemodulefactoryfunction.*/fn.define=function(id,deps,factory){

//codeoffunction…}上面是我从SeaJS源码中摘录出来的,define可以接收的参数分别是模块ID,依赖模块数组及工厂函数。我阅读源代码后发现define对于不同参数个数的解析规则如下:如果只有一个参数,则赋值给factory。如果有两个参数,第二个赋值给factory;第一个如果是array则赋值给deps,否则赋值给id。如果有三个参数,则分别赋值给id,deps和factory。但是,包括SeaJS的官方示例在内几乎所有用到define的地方都只传递一个工厂函数进去,类似与如下代码:?123define(function(require,exports,module){

//codeofthemodule...});个人建议遵循SeaJS官方示例的标准,用一个参数的define定义模块。那么id和deps会怎么处理呢?id是一个模块的标识字符串,define只有一个参数时,id会被默认赋值为此js文件的绝对路径。如下的a.js文件中使用define定义模块,则这个模块的ID会赋值为“/a.js”,没有特别的必要建议不要传入id。deps一般也不需要传入,需要用到的模块用require加载即可。工厂函数factory解析工厂函数是模块的主体和重点。在只传递一个参数给define时(推荐写法),这个参数就是工厂函数,此时工厂函数的三个参数分别是:require——模块加载函数,用于记载依赖模块。exports——接口点,将数据或方法定义在其上则将其暴露给外部调用。module——模块的元数据。这三个参数可以根据需要选择是否需要显示指定。下面说一下module。module是一个对象,存储了模块的元信息,具体如下:module.id——模块的ID。module.dependencies——一个数组,存储了此模块依赖的所有模块的ID列表。module.exports——与exports指向同一个对象。三种编写模块的模式第一种定义模块的模式是基于exports的模式:?12345678910111213141516define(function(require,exports,module){

vara=require('a');//引入a模块

varb=require('b');//引入b模块

vardata1=1;//私有数据

varfunc1=function(){//私有方法

returna.run(data1);

}

exports.data2=2;//公共数据

exports.func2=function(){//公共方法

return'hello';

}});上面是一种比较“正宗”的模块定义模式。除了将公共数据和方法附加在exports上,也可以直接返回一个对象表示模块,如下面的代码与上面的代码功能相同:?1234567891011121314151617define(function(require){

vara=require('a');//引入a模块

varb=require('b');//引入b模块

vardata1=1;//私有数据

varfunc1=function(){//私有方法

returna.run(data1);

}

return{

data2:2,

func2:function(){

return'hello';

}

};});如果模块定义没有其它代码,只返回一个对象,还可以有如下简化写法:?123456define({

data:1,

func:function(){

return'hello';

}});第三种方法对于定义纯JSON数据的模块非常合适。模块的寻址算法上文说过一个模块对应一个js文件,而载入模块时一般都是提供一个字符串参数告诉载入函数需要的模块,所以就需要有一套从字符串标识到实际模块所在文件路径的解析算法。SeaJS支持如下标识:绝对地址——给出js文件的绝对路径。如?1require("http://example/js/a");就代表载入“http://example/js/a.js”。相对地址——用相对调用载入函数所在js文件的相对地址寻找模块。例如在“http://example/js/b.js”中载入?1require("./c");则载入“http://example/js/c.js”。基址地址——如果载入字符串标识既不是绝对路径也不是以”./”开头,则相对SeaJS全局配置中的“base”来寻址,这种方法稍后讨论。注意上面在载入模块时都不用传递后缀名“.js”,SeaJS会自动添加“.js”。但是下面三种情况下不会添加:载入css时,如?1require("./module1-style.css");路径中含有”?”时,如?1require(<ahref="http://example/js/a.json?cb=func">http://example/js/a.json?cb=func</a>);路径以”#”结尾时,如?1require("http://example/js/a.json#");根据应用场景的不同,SeaJS提供了三个载入模块的API,分别是seajs.use,require和require.async,下面分别介绍。seajs.useseajs.use主要用于载入入口模块。入口模块相当于C程序的main函数,同时也是整个模块依赖树的根。上面在TinyApp小例子中,init就是入口模块。seajs.use用法如下:?12345678910111213//单一模式seajs.use('./a');

//回调模式seajs.use('./a',function(a){

a.run();});

//多模块模式seajs.use(['./a','./b'],function(a,b){

a.run();

b.run();});一般seajs.use只用在页面载入入口模块,SeaJS会顺着入口模块解析所有依赖模块并将它们加载。如果入口模块只有一个,也可以通过给引入sea.js的script标签加入”data-main”属性来省略seajs.use,例如,上面TinyApp的index.html也可以改为如下写法:?1234567891011<!DOCTYPEHTML><htmllang="zh-CN"><head>

<metacharset="UTF-8">

<title>TinyApp</title></head><body>

<pclass="content"></p>

<scriptsrc="./sea.js"data-main="./init"></script></body></html>这种写法会令html更加简洁。requirerequire是SeaJS主要的模块加载方法,当在一个模块中需要用到其它模块时一般用require加载:?1varm=require('/path/to/module/file');这里简要介绍一下SeaJS的自动加载机制。上文说过,使用SeaJS后html只要包含sea.js即可,那么其它js文件是如何加载进来的呢?SeaJS会首先下载入口模块,然后顺着入口模块使用正则表达式匹配代码中所有的require,再根据require中的文件路径标识下载相应的js文件,对下载来的js文件再迭代进行类似操作。整个过程类似图的遍历操作(因为可能存在交叉循环依赖所以整个依赖数据结构是一个图而不是树)。明白了上面这一点,下面的规则就很好理解了:传给require的路径标识必须是字符串字面量,不能是表达式,如下面使用require的方法是错误的:?123require('module'+'1');

require('Module'.toLowerCase());这都会造成SeaJS无法进行正确的正则匹配以下载相应的js文件。require.async上文说过SeaJS会在html页面打开时通过静态分析一次性记载所有需要的js文件,如果想要某个js文件在用到时才下载,可以使用require.async:?123require.async('/path/to/module/file',function(m){

//codeofcallback...});这样只有在用到这个模块时,对应的js文件才会被下载,也就实现了JavaScript代码的按需加载。SeaJS提供了一个seajs.config方法可以设置全局配置,接收一个表示全局配置的配置对象。具体使用方法如下:?123456789seajs.config({

base:'path/to/jslib/',

alias:{

'app':'path/to/app/'

},

charset:'utf-8',

timeout:20000,

debug:false});其中base表示基址寻址时的基址路径。例如base设置为”/js/3-party/”,则?1var$=require('jquery');会载入”/js/3-party/jquery.js”。alias可以对较长的常用路径设置缩写。charset表示下载js时script标签的charset属性。timeout表示下载文件的最大时长,以毫秒为单位。debug表示是否工作在调试模式下。要将现有JS库如jQuery与SeaJS一起使用,只需根据SeaJS的的模块定义规则对现有库进行一个封装。例如,下面是对jQuery的封装方法:?1234567891011121314151617181920212223define(function(){

//{{{jQuery原有代码开始/*!

*jQueryJavaScriptLibraryv1.6.1

*/

*

*Copyright2011,JohnResig

*DuallicensedundertheMITorGPLVersion2licenses.

*/license

*

*IncludesSizzle.js

*/

*Copyright2011,TheDojoFoundation

*ReleasedundertheMIT,BSD,andGPLLicenses.

*

*Date:ThuMay1215:04:362011-0400

*///...//}}}jQuery原有代码结束

return$.noConflict();});SeaJS本来集成了一个打包部署工具spm,后来作者为了更KISS一点,将spm拆出了SeaJS而成为了一个单独的项目。spm的核心思想是将所有模块的代码都合并压缩后并入入口模块,由于SeaJS本身的特性,html不需要做任何改动就可以很方便的在开发环境和生产环境间切换。但是由于spm目前并没有发布正式版本,所以本文不打算详细介绍,有兴趣的朋友可以参看其github项目主页\o"/seajs/spm/"/seajs/spm/。其实,由于每个项目所用的JS合并和压缩工具不尽相同,所以spm可能并不是完全适合每个项目。在了解了SeaJS原理后,完全可以自己写一个符合自己项目特征的合并打包脚本。一个完整的例子上文说了那么多,知识点比较分散,所以最后我打算用一个完整的SeaJS例子把这些知识点串起来,方便朋友们归纳回顾。这个例子包含如下文件:index.html——主页面。sea.js——SeaJS脚本。init.js——in

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论