這篇文章主要介紹了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會首先下載入口模塊,然後順著入口模塊使用正則表達式匹配代碼中所有的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) {