為企業提供網站平臺解決方案

178 7892 1916

QQ客服:點擊這里給我發消息 點擊這里給我發消息

最新動態:

常見問題

你的位置:首頁 > 建站知識 > 常見問題 > SeaJS使用詳細教程

SeaJS使用詳細教程

發布時間:2014-01-21 17:56作者:桂林螞蟻網絡網址:www.erpoxy.live瀏覽:
SeaJS使用詳細教程

一步步學會使用SeaJS 2.0


本文分為以下8步,熟悉之后就能夠熟練使用SeaJS,從此之后你的生活會變得更加輕松愉悅!
1、SeaJS是什么?
2、下載并檢閱SeaJS
3、建立工程和各種目錄
4、引入SeaJS庫
5、編寫自己的代碼
6、引入自己的代碼
7、壓縮合并
8、總結展望

 

--------------------------------------------------

 

1、SeaJS是什么?

 

你一定聽過前端模塊化開發吧?神馬,你沒聽過?我只能說你out了……
你應該知道Java的import吧?神馬,你又不知道?那你應該知道CSS中的import吧……
在這里我不想展開說前端模塊化的含義和價值,因為這里有一篇好文(https://github.com/seajs/seajs/issues/547),詳細說明了前端模塊化。

我知道你看到那么長的文章肯定會望而卻步,也許你是希望能夠快速開始敲代碼(程序員的通病……)。沒關系,如果實在讀不下去,只要記住模塊化要解決的問題即可:命名沖突、文件依賴關系。

這兩個鬧心的問題應該遇到過吧,如果沒遇到過……我只能說你太牛X了

好了,前端模塊化就扯到這里,寫過前端的人應該基本都知道JavaScript自身是不支持模塊化開發的,所以就有了SeaJS這款神器,為前端從業者提供了一個強大易用的模塊化開發工具。

 

 

 

2、下載并檢閱SeaJS

 

SeaJS現在已經是2.0版本啦,到這里下載:https://github.com/seajs/seajs

 

解壓后會看到下列目錄:

 

其中:
dist —— 壓縮好的、用于瀏覽器端的SeaJS代碼
docs —— 文檔
src —— 源代碼
package.json + Gruntfile.js —— Grunt構建工具所需要的文件,這個在第七步壓縮合并會介紹到
其他目錄或文件可以暫且不管

 

 

 

3、建立工程和各種目錄

 

準備工作已經完成,我們終于可以開始進行開發啦!來,跟我走:
a. 建立工程
用你最喜歡的IDE建立工程,名字為HelloSeaJS
b. 準備各種目錄
在這里把JavaScript、Image、CSS都放在統一的資源文件(assets)中,建好之后的目錄如下:

(我使用了Sublime2.0,在這里強烈推薦)

 

c. 把剛剛下好的seajs/dist中的文件都放在scripts/seajs目錄下

注意:SeaJS會根據自身的URI來決定URL base,而SeaJS在加載其他模塊的時候會根據這個URL base來計算路徑。SeaJS會忽略掉seajs、seajs/2.0.0/seajs這兩種目錄,照上述的目錄結構,此處的URL base就是HelloSeaJS/assets/scripts,這樣其他模塊就可以與seajs目錄并行存放。

 

至此,工程和文件都已準備完成。

 

 

 

4、引入SeaJS庫

 

與引入其他js庫并無太大區別:
<script src="assets/scripts/seajs/sea.js" id="seajsnode"></script>
你可能注意到,這里加上了id="seajsnode",原因如下:
a. SeaJS加載自身的script標簽的其他屬性(如data-config、data-main)等來實現不同的功能

b. SeaJS內部通過document.getElementById("seajsnode")來獲取這個script標簽(其實SeaJS內部還有一種方式,不過另一種方式的效率比較低,所以不推薦,如果有興趣,可以看一下源碼https://github.com/seajs/seajs/blob/master/src/util-path.js

 

 

 

 

5、編寫自己的代碼

 

這里作為示范,只做了一個非常簡單的效果,點擊查看:http://liuda101.github.io/HelloSeaJS/
在編寫自己代碼的時候,要時刻記住”模塊化“,而操作起來也非常簡單,因為在SeaJS中一個文件就是一個模塊。
下面是代碼邏輯的模塊application.js:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
define(function(require,exports,module){
   
     var util = {};
   
     var colorRange = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'];
   
     util.randomColor = function(){
          return '#' +
               colorRange[Math.floor(Math.random() * 16)] +
               colorRange[Math.floor(Math.random() * 16)] +
               colorRange[Math.floor(Math.random() * 16)] +
               colorRange[Math.floor(Math.random() * 16)] +
               colorRange[Math.floor(Math.random() * 16)] +
               colorRange[Math.floor(Math.random() * 16)];
     };
   
   
     var helloSeaJS = document.getElementById('hello-seajs');
     helloSeaJS.style.color = util.randomColor();
     window.setInterval(function(){
          helloSeaJS.style.color = util.randomColor();
     },1500);
});
我們看到,所有代碼都放在define(function(require,exports,module){});函數體里面。
define是SeaJS定義的一個全局函數,用來定義一個模塊。
至于require,exports,module都是什么,可以暫且不管,到此,我們的代碼已經完成,很簡單吧。嗯,花個幾十秒鐘,看一下代碼。
……
看完之后,你會說,這算什么啊!這就完了么?
不要怪我,為了簡單易懂,我們就按照”一步步“的節奏慢慢來。

隨著代碼的增多,你肯定會遇到util越來越多的情況。很好,這樣看來,我們就有了兩個模塊:util模塊和application模塊。SeaJS中,文件即模塊,所以當然要將其分為兩個文件。先看util.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
define(function(require,exports,module){
     var util = {};
   
     var colorRange = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'];
   
     util.randomColor = function(){
          return '#' +
               colorRange[Math.floor(Math.random() * 16)] +
               colorRange[Math.floor(Math.random() * 16)] +
               colorRange[Math.floor(Math.random() * 16)] +
               colorRange[Math.floor(Math.random() * 16)] +
               colorRange[Math.floor(Math.random() * 16)] +
               colorRange[Math.floor(Math.random() * 16)];
     };
   
     module.exports = util;
});

 

除了define之外,我們看到module.exports = util;這一句比較特殊。這句是在說,我util模塊向外暴露的接口就這些,其他所有的東西都是我內部用的,爾等就無需擔心了,我會照顧好的。

再看application.js:

1
2
3
4
5
6
7
8
9
10
define(function(require,exports,module){
   
     var util = require('./util');
   
     var helloSeaJS = document.getElementById('hello-seajs');
     helloSeaJS.style.color = util.randomColor();
     window.setInterval(function(){
          helloSeaJS.style.color = util.randomColor();
     },1500);
});

 

我們看到var util = require('./util');這句比較特殊。這句就是在說,我application模塊由于業務需要,想請util模塊來幫忙,所以把util給require進來。

 

 

至此,我們經歷了一個模塊到兩個模塊的轉變,在日后漫長的日子中,我們的模塊也許會越來越多,不過不用擔心,有了SeaJS提供的define、require、module.exports,我們都可以方便的應對。

 

 

 

6、引入自己的代碼

 

你看到這個小標題,你可能會極力的鄙視我,這等工作還需要你來示范?于是,你啪啪啪啪,在引入SeaJS的script標簽后引入了util.js和application.js:
<script src="assets/scripts/application/util.js"></script>
<script src="assets/scripts/application/application.js"></script>
然后你不停的F5……

你看不到效果吧?這就是這個小節存在的理由。

 

SeaJS提供了模塊化的能力,前面我們已經看到了SeaJS定義模塊、引用模塊的方法,而這里就要用到SeaJS加載并啟動模塊的兩種方式:
a、使用data-main
為<script src="assets/scripts/seajs/sea.js" id="seajsnode"></script>添加data-main="application/application"屬性即可:
<script src="assets/scripts/seajs/sea.js" id="seajsnode" data-main="application/application"></script>
SeaJS會根據data-main指定的模塊來作為整個應用的入口模塊。SeaJS找到這個模塊之后,就會加載執行這個模塊對應的文件。
那么,SeaJS又是怎么找到這個文件呢?也就是說,這個模塊對應的加載路徑是多少?
“算法”是:SeaJS_URL_base + data-main
如上文,該例子的SeaJS_URL_base是HelloSeaJS/assets/scripts/

那么,加載路徑就是HelloSeaJS/assets/scripts/application/application.js(SeaJS會自動加上.js后綴)

 

b、使用seajs.use
在<script src="assets/scripts/seajs/sea.js" id="seajsnode">后面加上:
<script> seajs.use("application/application"); </script>
其實這兩種效果在這個例子中是一樣的,data-main通常用在只有一個入口的情況,use可以用在多個入口的情況,具體用法,看這里:https://github.com/seajs/seajs/issues/260

如果你對你的程序有完全的控制權,建議使用data-main的方式,這樣整個頁面就只有一段script標簽!作為一名前端開發人員,我不得不驚嘆:干凈、完美!

 

無論使用哪種方式,跟著我一起F5一下!
在打開Chrome的debug工具,查看Network這個tab:

我們看到,SeaJS已經幫我們加載好了application.js和util.js,舒服吧~
嗯,我第一次試用SeaJS的時候,到這里也感到了無比的舒心

 

 

 

7、壓縮合并

 

正當我伸伸懶腰,打算上個廁所的時候,突然想到一件事情:如果模塊越來越多,那么多文件都要分開加載?那豈不嚴重影響性能!?(啥,你不知道為啥?)
要壓縮合并JavaScript呀!于是,我強忍住那股液體,開始用YUICompressor來壓縮,并手動合并了兩個文件。
這里就不展示結果了,因為很蛋疼,完全對不住我剛才忍住液體的勇氣!結果當然是,失敗。
為什么會失敗呢?自己想了想,同時打開壓縮后的代碼一看,才發現原因:

壓縮后之后,require變量變成了a變量。SeaJS是通過require字面來判斷模塊之間的依賴關系的,所以,require變量不能被簡化。

 

嗯,SeaJS已經替我們想到了這個問題,于是我們就采用SeaJS提供的方式來合并壓縮吧(當然你也可以自己用別的方式壓縮)。

SeaJS在2.0之前,是采用SPM作為壓縮合并工具的,到了2.0,改為Grunt.js,SPM變為包管理工具,類似NPM(不知道NPM?Google一下吧)

 

自動化不僅是科技帶給社會的便利,也是Grunt帶給前端的瑞士軍刀。使用Grunt,可以很方便的定制各種任務,如壓縮、合并等。使用Grunt之前,需要安裝node環境和grunt工具,Google一下,十分鐘后回來。

……

 

Grunt最核心的就兩個部分,package.json、Gruntfile.js。

 

a. package.json

    Grunt把一個項目/目錄視為一個npm模塊,package.json就是用來描述這個模塊的信息,包括name、version、author等等。
這里強調一下,Grunt既然將該目錄視為一個模塊,那么該模塊當然可以依賴其他模塊。
我們看本示例的:
1
2
3
4
5
6
7
8
9
10
11
12
{
     "name" : "HelloSeaJS",
     "version" : "1.0.0",
     "author" : "Qifeng Liu",
     "devDependencies" : {
          "grunt" : "0.4.1",
          "grunt-cmd-transport" : "0.1.1",
          "grunt-cmd-concat" : "0.1.0",
          "grunt-contrib-uglify" : "0.2.0",
          "grunt-contrib-clean" : "0.4.0"
     }
}

 

 

devDependencies就是用來描述自身所依賴的模塊
其中:
grunt模塊用來跑Gruntfile.js中定義的任務
grunt-cmd-transport模塊用來對SeaJS定義的模塊進行依賴提取等任務
grunt-cmd-concat模塊用來對文件進行合并
grunt-contrib-uglify模塊用來壓縮JavaScript

grunt-contrib-clean模塊用來清除臨時目錄

 

b. Gruntfile.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
module.exports = function(grunt){
   
     grunt.initConfig({
          transport : {
               options : {
                    format : 'application/dist/{{filename}}'  //生成的id的格式
               },
               application : {
                    files : {
                         '.build' : ['application.js','util.js']   //將application.js、util.js合并且提取依賴,生成id,之后放在.build目錄下
                    }
               }
          },
          concat : {
               main : {
                    options : {
                         relative : true
                    },
                    files : {
                         'dist/application.js' : ['.build/application.js'],  // 合并.build/application.js文件到dist/application.js中
                         'dist/application-debug.js' : ['.build/application-debug.js']
                    }
               }
          },
          uglify : {
               main : {
                    files : {
                         'dist/application.js' : ['dist/application.js'//對dist/application.js進行壓縮,之后存入dist/application.js文件
                    }
               }
          },
          clean : {
               build : ['.build'//清除.build文件
          }
     });
   
     grunt.loadNpmTasks('grunt-cmd-transport');
     grunt.loadNpmTasks('grunt-cmd-concat');
     grunt.loadNpmTasks('grunt-contrib-uglify');
     grunt.loadNpmTasks('grunt-contrib-clean');
   
     grunt.registerTask('build',['transport','concat','uglify','clean'])
};

 

定義好兩個文件之后,就可以進入到application目錄下,首先運行:
npm install
該命令會下載好package.json中依賴的模塊
然后運行
grunt build

該命令會運行grunt.registerTask方法中指定的任務

 

不出差錯的話,會在application目錄下生成一個dist目錄,里面包含了合并但沒壓縮的application-debug.js和合并且壓縮好的application.js。
修改index.html的
<script src="assets/scripts/seajs/sea.js" id="seajsnode" data-main="application/application"></script>
<script src="assets/scripts/seajs/sea.js" id="seajsnode" data-main="application/dist/application"></script>
大功告成!

 

 

 

8、總結展望

 

SeaJS秉著簡單實用的原則,API設計職責單一,使用起來得心應手。
SeaJS為前端提供了模塊化能力,可以簡單優雅的解決命名沖突、依賴關系等常見且棘手的問題。通過使用SeaJS,我的生活質量一下次上升好幾個檔次。
當然,除了本文介紹的,SeaJS還有一些其他功能,相信只要你入了門,肯定能夠迅速掌握,這里給個鏈接http://seajs.org/docs/#docs
其實,許多語言自身已經有了模塊化的功能,如Java的import,C++的#include等,但是由于各種原因,JavaScript自身并沒有這個功能。雖然借助于SeaJS可以很方便的進行模塊化開發了,但總覺得這個能力應該是語言自身的。好在,下個版本的JavaScript貌似在計劃引入模塊化的概念,讓我們拭目以待吧!

 

 

 

最后,感謝SeaJS作者玉伯。

 

 

PS,本文參考了SeaJS提供的使用范例https://github.com/seajs/examples/tree/master/static/hello


今天晚上平特三连肖是哪几个