本文轉自張洋,因為SeaJS更新版本很快,所以原文中很多地方不太適用,在這里發布一個更新版。
前言
SeaJS是一個遵循CommonJS規范的JavaScript模塊加載框架,可以實現JavaScript的模塊化開發及加載機制。使用SeaJS可以提高JavaScript代碼的可讀性和清晰度,解決目前JavaScript編程中普遍存在的依賴關系混亂和代碼糾纏等問題,方便代碼的編寫和維護。
SeaJS本身遵循KISS(Keep it Simple,Stupid)理念進行開發,后續的幾個版本更新也都是吵着這個方向邁進。
如何使用SeaJS
下載及安裝在這里不贅述了,不了解的請查詢官網。
基本開發原則
- 一切皆為模塊:SeaJS中的模塊概念有點類似於面向對象中的類--模塊可以擁有數據和方法,數據和方法可以定義為公共或私有,公共數據和方法可以供別的模塊調用。
- 每個模塊應該都定義在一個單獨的js文件中,即一個對應一個模塊。
模塊的定義和編寫
模塊定義函數define
SeaJS中使用define
函數定義一個模塊。define可以接收三個參數:
/**
* Defines a module.
* @param {string=} id The module id.
* @param {Array.|string=} deps The module dependencies.
* @param {function()|Object} factory The module factory function.
*/
fn.define = function(id, deps, factory) {
//code of function…
}
define可以接收的參數分別是模塊ID,依賴模塊數組及工廠函數。
- 如果只有一個參數,則賦值給factory
- 如果有兩個參數,第二個賦值給factory,第一個如果是數組則賦值給deps,否則賦值給id
- 如果有三個參數,則分別賦值
但是,包括SeaJS官網示例在內幾乎所有用到define的地方都只傳遞一個工廠函數進去,類似於如下代碼:
define(function(require,exports,module){
//code of the module
})
個人建議遵循SeaJS官方示例的標准,用一個參數的define定義模塊。那么id和deps會怎么處理呢?
id是一個模塊的標識字符串,define只有一個參數時,id會被默認賦值為此js文件的絕對路徑。如example.com下的a.js文件中使用define定義模塊,則這個模塊的ID會賦值為 http://example.com/a.js ,沒有特別的必要建議不要傳入id。deps一般也不需要傳入,需要用到的模塊用require加載即可。
工廠函數factory解析
工廠函數是模塊的主體和重點。它的三個參數分別是:
- require:模塊加載函數,用於記載依賴模塊
- exports:接口點,將數據或方法定義在其上則將其暴露給外部調用
- module:模塊的元數據
這三個參數可以根據需要選擇是否需要顯示指定。
module是一個對象,存儲了模塊的元信息,具體如下:
- module.id:模塊的ID
- module.dependencies:一個數組,存儲了此模塊依賴的所有模塊的ID列表。
- module.exports:與exports指向同一個對象
三種編寫模塊的模式
第一種是基於exports的模式:
define(function(require,exports,module){
var a=require('a');
var b=require('b'); //引入模塊
var data1=1; //私有數據
var fun1=function(){//私有方法
return a.run(data1);
}
exports.data2=2; //公有數據
exports.fun2=function(){
return 'hello';
}
})
上面是一種比較“正宗”的模塊定義模式。除了講公共數據和方法附加在exports上,也可以直接返回一個對象表示模塊,如下面的代碼與上面的代碼功能相同:
define(function(require){
var a=require('a');
var b=require('b'); //引入模塊
var data1=1;
var fun1=function(){
return a.run(data1);
}
return{
data2:2,
fun2:function(){
return 'hello';
}
}
})
如果模塊定義沒有其他代碼,只返回一個對象,還可以有如下簡化寫法:
define({
data2:2,
fun2:function(){
return 'hello';
}
})
第三種寫法對於定義純JSON數據的模塊非常合適。
根據應用場景的不同,SeaJS提供了三個載入模塊的API,分別是:seajs.use,require和require.async。
seajs.use
seajs.use主要用於載入入口模塊。入口模塊相當於C語言的main函數,同時也是整個模塊依賴樹的根。seajs.use
的用法如下:
//第一模式
seajs.use('./a');
//回調模式
seajs.use('./a',function(a){
a.run();
})
//多模塊模式
seajs.use(['./a','./b'],function(a,b){
a.run();
b.run();
})
其中多模塊的用法和KISSY中的模塊加載方法類似,不虧是一個人寫的啊!
一般seajs.use只用在頁面載入入口模塊,SeaJS會順着入口模塊解析所有依賴模塊並將它們加載。如果入口模塊只有一個,也可以通過給引入seajs的script標簽加入“data-main”屬性來省略seajs.use,例如一下寫法:
<!DOCTYPE HTML>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>TinyApp</title>
</head>
<body>
<p class="content"></p>
<script src="./sea.js" data-main="./init"></script>
</body>
</html>
require
require是seajs主要的模塊加載方法,當在一個模塊中需要用到其他模塊時一般用require加載:
var m=require('./a');
require.async
上文說過seajs會在html頁面打開時通過靜態分析一次性記載所有需要的js文件,如果想要某個js文件在用時才加載,可以使用require.async。
這樣只有在用到這個模塊時,對應的js文件才會被下載,也就實現了JavaScript代碼的按需加載。
SeaJS的全局配置
seajs提供了一個seaj.configd的方法可以設置全局配置,接收一個表示全局配置的配置對象,具體方法如下:
seajs.config({
base:'path',
alias:{
'app':'path/app/'
},
charset:'utf-8',
timeout:20000,
debug:false
})
其中,
- base表示基址路徑
- alias可以對較長的常用路徑設置縮寫
- charset表示下載js時script標簽的charset屬性。
- timeout表示下載文件的最大時長,以毫秒為單位。
Seajs如何與現有的JS庫配合使用
要將現有的JS庫與seajs一起使用,只需根據seajs的模塊定義規則對現有庫進行一個封裝。例如,下面是對jQuery的封裝方法:
define(function(){
/*
此處為jquery源碼
*/
})
一個完整的例子:
上文說了那么多,知識點比較分散,所以最后我打算用一個完整的SeaJS例子把這些知識點串起來,方便朋友們歸納回顧。這個例子包含如下文件:
- index.html 主頁面
- sea.js
- jquery.js
- init.js init模塊,入口模塊,依賴data、jquery、style三個模塊,又主頁面載入
- data.js data模塊,純json數據模塊
- style.css css樣式表
html:
<!DOCTYPE HTML>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="content">
<p class="author"></p>
<p class="blog"><a href="#">Blog</a></p>
</div>
<script src="sea.js"></script>
<script>
seajs.use('init');
</script>
</body>
</html>
javascript:
//init.js
define(function(require, exports, module) {
var $ = require('./jquery');
var data = require('./data');
var css = require('./style.css');
$('.author').html(data.author);
$('.blog').attr('href', data.blog);
});
//data.js
define({
author: 'ZhangYang',
blog: 'http://blog.codinglabs.org'
});
css:
.author{color:red;font-size:10pt;}
.blog{font-size:10pt;}
請注意:
1.請講jquery.js源碼文件包含在seajs模塊加載代碼中;
2.在Sea.js < 2.3.0版本之前是可以加載css文件的,新版本中此功能移除,為了兼容考慮,加載css功能將作為一個插件存在。
使用方法
- 可以在sea.js標簽后引入這個插件使用
- 也可以將插件代碼混入sea.js當中
- 和seajs-style的區別
- seajs-css是使 Sea.js 能夠加載一個css文件,和link標簽一樣
- seajs-style是指提供一個seajs.importStyle方法用於加載一段 css 字符串