SeaJS入門教程系列之使用SeaJS(二)

來源:互聯網
上載者:User

SeaJS入門教程系列之使用SeaJS(二)

 這篇文章主要介紹了SeaJS入門教程系列之使用SeaJS,著重介紹了SeaJS的使用方法、關鍵方法的使用等,需要的朋友可以參考下

下載及安裝

 

要在項目中使用SeaJS,你所有需要做的準備工作就是下載sea.js然後放到你項目的某個位置。

SeaJS項目目前託管在GitHub上,首頁為 https://github.com/seajs/seajs/ 。可以到其git庫的build目錄下下載sea.js(已壓縮)或sea-debug.js(未壓縮)。

下載完成後放到項目的相應位置,然後在頁面中通過<script>標籤引入,你就可以使用SeaJS了。

 

SeaJS基本開發原則

 

在討論SeaJS的具體使用前,先介紹一下SeaJS的模組化理念和開發原則。

使用SeaJS開發JavaScript的基本原則就是:一切皆為模組。引入SeaJS後,編寫JavaScript代碼就變成了編寫一個又一個模組,SeaJS中模組的概念有點類似於物件導向中的類——模組可以擁有資料和方法,資料和方法可以定義為公用或私人,公用資料和方法可以供別的模組調用。

另外,每個模組應該都定義在一個單獨js檔案中,即一個對應一個模組。

下面介紹模組的編寫和調用。

 

模組的定義及編寫

 

模組定義函數define

SeaJS中使用“define”函數定義一個模組。因為SeaJS的文檔並沒有關於define的完整參考,所以我閱讀了SeaJS原始碼,發現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…

}

 

上面是我從SeaJS源碼中摘錄出來的,define可以接收的參數分別是模組ID,相依模組數組及工廠函數。我閱讀原始碼後發現define對於不同參數個數的解析規則如下:

如果只有一個參數,則賦值給factory。

如果有兩個參數,第二個賦值給factory;第一個如果是array則賦值給deps,否則賦值給id。

如果有三個參數,則分別賦值給id,deps和factory。

但是,包括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解析

 

工廠函數是模組的主體和重點。在只傳遞一個參數給define時(推薦寫法),這個參數就是工廠函數,此時工廠函數的三個參數分別是:

1.require——模組載入函數,用於記載相依模組。

2.exports——介面點,將資料或方法定義在其上則將其暴露給外部調用。

3.module——模組的中繼資料。

這三個參數可以根據需要選擇是否需要顯示指定。

下面說一下module。module是一個對象,儲存了模組的元資訊,具體如下:

1.module.id——模組的ID。

2.module.dependencies——一個數組,儲存了此模組依賴的所有模組的ID列表。

3.module.exports——與exports指向同一個對象。

 

三種編寫模組的模式

 

第一種定義模組的模式是基於exports的模式:

 

 代碼如下:

define(function(require, exports, module) {

    var a = require('a'); //引入a模組

    var b = require('b'); //引入b模組

 

    var data1 = 1; //私人資料

 

    var func1 = function() { //私人方法

        return a.run(data1);

    }

 

    exports.data2 = 2; //公用資料

 

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

        return 'hello';

    }

});

 

 

上面是一種比較“正宗”的模組定義模式。除了將公用資料和方法附加在exports上,也可以直接返回一個對象表示模組,如下面的代碼與上面的代碼功能相同:

 

 代碼如下:define(function(require) {

    var a = require('a'); //引入a模組

    var b = require('b'); //引入b模組

 

    var data1 = 1; //私人資料

 

    var func1 = function() { //私人方法

        return a.run(data1);

    }

 

    return {

        data2: 2,

        func2: function() {

            return 'hello';

        }

    };

});

 

如果模組定義沒有其它代碼,只返回一個對象,還可以有如下簡化寫法:

 代碼如下:define({

    data: 1,

    func: function() {

        return 'hello';

    }

});

第三種方法對於定義純JSON資料的模組非常合適。

 

模組的載入和引用

 

模組的定址演算法

上文說過一個模組對應一個js檔案,而載入模組時一般都是提供一個字串參數告訴載入函數需要的模組,所以就需要有一套從字串標識到實際模組所在檔案路徑的解析演算法。SeaJS支援如下標識:

絕對位址——給出js檔案的絕對路徑。

 

如:

 

 代碼如下:require("http://example/js/a");

就代表載入 http://example/js/a.js 。

相對位址——用相對調用載入函數所在js檔案的相對位址尋找模組。

例如在 http://example/js/b.js 中載入

複製代碼 代碼如下:require("./c");

則載入 http://example/js/c.js 。

基址地址——如果載入字串標識既不是絕對路徑也不是以”./”開頭,則相對SeaJS全域配置中的“base”來定址,這種方法稍後討論。

注意上面在載入模組時都不用傳遞尾碼名“.js”,SeaJS會自動添加“.js”。但是下面三種情況下不會添加:

載入css時,如:

複製代碼 代碼如下:require("./module1-style.css");

路徑中含有”?”時,如:

複製代碼 代碼如下:require(<a href="http://example/js/a.json?cb=func">http://example/js/a.json?cb=func</a>);

路徑以”#”結尾時,如:

複製代碼 代碼如下:require("http://example/js/a.json#");

根據應用情境的不同,SeaJS提供了三個載入模組的API,分別是seajs.use,require和require.async,下面分別介紹。

 

seajs.use

 

seajs.use主要用於載入入口模組。入口模組相當於C程式的main函數,同時也是整個模組依賴樹的根。上面在TinyApp小例子中,init就是入口模組。seajs.use用法如下:

 

代碼如下:

//單一模式

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也可以改為如下寫法:

 代碼如下:

<!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>

 

這種寫法會令html更加簡潔。

 

 

require

 

require是SeaJS主要的模組載入方法,當在一個模組中需要用到其它模組時一般用require載入:

 

 代碼如下:var m = require('/path/to/module/file');

這裡簡要介紹一下SeaJS的自動載入機制。上文說過,使用SeaJS後html只要包含sea.js即可,那麼其它js檔案是如何載入進來的呢?SeaJS會首先下載入口模組,然後順著入口模組使用Regex符合代碼中所有的require,再根據require中的檔案路徑標識下載相應的js檔案,對下載來的js檔案再迭代進行類似操作。整個過程類似圖的遍曆操作(因為可能存在交叉循環相依性所以整個依賴資料結構是一個圖而不是樹)。

明白了上面這一點,下面的規則就很好理解了:

傳給require的路徑標識必須是字串字面量,不能是運算式,如下面使用require的方法是錯誤的:

複製代碼 代碼如下:require('module' + '1');

require('Module'.toLowerCase());

這都會造成SeaJS無法進行正確的正則匹配以下載相應的js檔案。

 

require.async

 

上文說過SeaJS會在html頁面開啟時通過靜態分析一次性記載所有需要的js檔案,如果想要某個js檔案在用到時才下載,可以使用require.async:

 代碼如下:require.async('/path/to/module/file', function(m) {

    //code of callback...

});

這樣只有在用到這個模組時,對應的js檔案才會被下載,也就實現了JavaScript代碼的按需載入。

 

SeaJS的全域配置

SeaJS提供了一個seajs.config方法可以設定全域配置,接收一個表示全域配置的設定物件。具體使用方法如下:

 

 代碼如下:seajs.config({

    base: 'path/to/jslib/',

    alias: {

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

    },

    charset: 'utf-8',

    timeout: 20000,

    debug: false

});

其中base表示基址定址時的基址路徑。例如base設定為 http://example.com/js/3-party/ ,則:

複製代碼 代碼如下:var $ = require('jquery');

會載入 http://example.com/js/3-party/jquery.js 。

alias可以對較長的常用路徑設定縮寫。

charset表示下載js時script標籤的charset屬性。

timeout表示下載檔案的最大時間長度,以毫秒為單位。

debug表示是否工作在偵錯模式下。

 

 

SeaJS如何與現有JS庫配合使用

 

要將現有JS庫如jQuery與SeaJS一起使用,只需根據SeaJS的的模組定義規則對現有庫進行一個封裝。例如,下面是對jQuery的封裝方法:

 

 代碼如下:define(function() {

 

//{{{jQuery原有代碼開始

/*!  

 * jQuery JavaScript Library v1.6.1

 * http://jquery.com/

 *

 * Copyright 2011, John Resig

 * Dual licensed under the MIT or GPL Version 2 licenses.

 * http://jquery.org/license

 *

 * Includes Sizzle.js

 * http://sizzlejs.com/

 * Copyright 2011, The Dojo Foundation

 * Released under the MIT, BSD, and GPL Licenses.

 *

 * Date: Thu May 12 15:04:36 2011 -0400

 */

//...

//}}}jQuery原有代碼結束

 

return $.noConflict();

});

 

 

SeaJS項目的打包部署

 

SeaJS本來整合了一個打包部署工具spm,後來作者為了更KISS一點,將spm拆出了SeaJS而成為了一個單獨的項目。spm的核心思想是將所有模組的代碼都合并壓縮後併入入口模組,由於SeaJS本身的特性,html不需要做任何改動就可以很方便的在開發環境和生產環境間切換。但是由於spm目前並沒有發布正式版本,所以本文不打算詳細介紹,有興趣的朋友可以參看其github項目首頁 https://github.com/seajs/spm/。

其實,由於每個項目所用的JS合并和壓縮公用程式不盡相同,所以spm可能並不是完全適合每個項目。在瞭解了SeaJS原理後,完全可以自己寫一個符合自己項目特徵的合并打包指令碼。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.