前端框架 seajs 使用總結

CMD 模塊定義規範

  • seajs中,所有的javascript都遵循CMD模塊定義規範。該規範明確定義了模塊的定義格式和模塊依賴的規則說明。
  • define.cmd : 一個空對象,可以用來判斷當前頁面是否存在cmd模塊加載器,調用方法如下:
if(typeof define.cmd ==="undefined" || define.cmd){
    //Seajs存在cmd模塊加載器
}
  • 與 RequireJS 的 AMD 規範相比,CMD 規範儘量保持簡單,並與 CommonJS 和 Node.js 的 Modules 規範保持了很大的兼容性
seajs的特點

  • 簡單友好的模塊定義規範:遵循CMD規範。
  • 簡單直觀的代碼組織方式:依賴自動加載,配置簡潔清晰。

seajs的兼容性

Chrome 3+ ✔ Firefox 2+ ✔ Safari 3.2+ ✔ Opera 10+ ✔ IE 5.5+ ✔

理論上適用於任何瀏覽器,包括Mobile

seajs的配置
seajs.config({
    // 別名配置
    alias: {
        'es5-safe': 'gallery/es5-safe/0.9.3/es5-safe',
        'json': 'gallery/json/1.0.2/json',
        'jquery': 'jquery/jquery/1.10.1/jquery'
    },
    // 路徑配置
    paths: {
        'gallery': 'https://a.alipayobjects.com/gallery'
    },
    // 變量配置
    vars: {
        'locale': 'zh-cn'
    },
    // 映射配置
    map: [
        ['http://example.com/js/app/', 'http://localhost/js/app/']
    ],
    // 預加載項
    preload: [
        Function.prototype.bind ? '' : 'es5-safe',
        this.JSON ? '' : 'json'
    ],
    // 調試模式
    debug: true,
    // Sea.js 的基礎路徑
    base: 'http://example.com/path/to/base/',
    // 文件編碼
    charset: 'utf-8'
});

alias Object
可以簡化較長模塊標示的書寫。
seajs.config({
   // 別名配置
    alias: {
        'es5-safe': 'gallery/es5-safe/0.9.3/es5-safe',
        'json': 'gallery/json/1.0.2/json',
        'jquery': 'jquery/jquery/1.10.1/jquery'
    }
});
模塊定義:
define(function(require, exports , module){
    var $ = require("jquery");
    //==>加載的是http://example.com/path/to/base/jquery/jquery/1.10.1/jquery.js
});

path Object
如果依賴層次較深,或者跨目錄調用模塊,path可以簡化書寫。
path 可以結合alias一起使用。
seajs.config({
    // 路徑配置
    paths: {
        'gallery': 'https://a.alipayobjects.com/gallery'
    },
});
模塊定義:
define(function(require,exports, module){
    var json = require("gallery/jsonparser");
    //==> 加載的是https://a.alipayobjects.com/gallery/jsonparser.js
});

vars Object
有些模塊需要在運行時才能確定,可以使用vars指定。
vars 配置的是模塊標識中的變量值,在模塊標識中用 {key} 來表示變量。

seajs.config({
// 變量配置
    vars: {
        'local': 'zh-cn'
    },
});
模塊定義
define(function(require, exports, module){
    var language_config = require("language/{local}.js");
    console.log(language_config);//獲取中文配置文件
});

map Array
路由模塊路徑。
seajs.config({
    // 映射配置
    map: [
        ['http://example.com/js/app/', 'http://localhost/js/app/'],
        ['.js','-debg.js']
    ],
});

define(function(require, exports, module){
    var m_a = require("./a");
    //==>加載的是./a-debug.js
});

preLoad Array
預加載一些公共模塊或者指定模塊
seajs.config({
    // 預加載項
    preload: [
        Function.prototype.bind ? '' : 'es5-safe',
        this.JSON ? '' : 'json'
    ],
});
preLoad中的配置,需要等到use時才加載
seajs.use("./b",function(){
    //在加載b模塊之前,預加載項已經加載完成。
});
preLoad中的配置,無法保證模塊定義中已經加載完成並執行完成。

debug String
值爲 true 時,加載器不會刪除動態插入的 script 標籤。插件也可以根據 debug 配置,來決策 log 等信息的輸出。

base String
Sea.js 在解析頂級標識時,會相對 base 路徑來解析。

charset String | Function
獲取模塊文件時,<script>  <link> 標籤的 charset 屬性。 默認是 utf-8
charset還可以是函數:
seajs.config({
    charset: function(url) {
        // xxx 目錄下的文件用 gbk 編碼加載
        if (url.indexOf('http://example.com/js/xxx') === 0) {
            return 'gbk';
        }
        // 其他文件用 utf-8 編碼
        return 'utf-8';
    }
});

注意:seajs.config 可以多次執行,每次執行都會對配置項進行合併操作。
config 會自動合併不存在的項,對存在的項則進行覆蓋。
建議seajs.config所在的js文件
獨立成一個文件時,一般通過 script 標籤在頁面中同步引入。

模塊定義(define Function

定義函數:
函數:define(factory)
其中,define方法是全局方法,作用域是window;factory可以是字符串,對象或者函數。

Factory類型:
  • 字符串或者對象。
   define({"username":"fol","age":"23"});    //factory是對象類型
    define("I love zhuzhou");    //factory是字符串類型
    如果模塊的factory類型是字符串或者對象,那麼該模塊對外提供的接口(輸出)就是字符串或者對象本身。
  • 函數
        定義格式1:
       
define(function(require, exports, module){
        //todo
   });
      如果factory的類型是函數,那麼給函數就是該模塊的構造函數,執行該函數可以得到模塊對外提供接口。
      factory默認傳入的參數是require, exports, module。
      這種模塊定義方式未指定模塊id,模塊依賴列表。
    
      定義格式2:
      define(id? , deps?, factory?)
      模塊定義也可以接受兩個以上參數,其中id定義模塊的id,deps聲明模塊依賴的其他模塊列表(Array)。
      define("user", ["jquery", "ajax", "upload", "json"], function(require, exports, module){
       // todo 
   });
    注意:id 和 deps參數是可選參數,可以通過構建工具自動生成。
    
模塊引用(require Function

模塊加載函數:
函數:require( id? )
其中,require對象是factory的第一個參數,同樣,require函數也是全局函數,作用域是window;
id是模塊標識,一般在模塊定義函數中被調用,用來獲取其他模塊提供的接口。
define(function( require, exports, module ) {
    var $ = require("jquery");  //引入jquery模塊
    $(document).ready(function(){
        $("#bt").on("click", function(){
              console.log("the bt is clicked");
        });
    });
});

異步加載:
函數:require.async( id?, callback? )
其中,id是模塊的標識,callback是模塊異步加載完成後的回調函數。
define(function(require, exports, module){
    //異步加載單個模塊
    require.async("plugins/bootstrap", function(b){
        b.doSomething();
    });
    //異步加載多個模塊
    require.async(["./utils/datepicker","./utils/colorpicker"], function(datepicker, colorpicker){
        datepicker.init();
        colorpicker.init();
    });
});
注意:require()是同步執行的,require.async()是異步回調執行,require.async用來執行可以延遲加載執行的模塊。

路徑解析:
函數:require.resolve(id?)
其中,id 是模塊的唯一標識,只用來解析模塊的絕對路徑。
define(function(require, exports, module){
    val jqueryPath = require.resolve("jquery");    //解析jquery的絕對路徑    
    //http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.js
});

seajs 三個對象

exports Object
exports 是一個對象,負責對外提供模塊接口。
define(function(require, exports, module){
      function trim() {
            return this.replace(/(^\s*)|(\s*$)/g, "")
      }
      exports.trim = trim;    //把內部函數暴露給其他模塊
      exports.config = {"username":"foo", "age":"23"};//把內部對象暴露給其他模塊
});

除了使用exports 對象對外提供接口外,還可以使用return直接對外提供接口
define(function(require, exports, module){
      function trim() {
            return this.replace(/(^\s*)|(\s*$)/g, "")
      }
      return {
        "trim":trim,
        "config":{"username":"foo", "age":23}
      }
});
如果模塊中return語句是唯一的代碼,那麼可以使用define({})簡化模塊定義:
define({
   "trim":function(){
        
return this.replace(/(^\s*)|(\s*$)/g, "")
    },
    "config":{"username":"foo","age":23}
}
);
上面的格式可以適合定義JSONP模塊。

注意:不能對exports重新賦值,這樣雖然不會影響到module.exports 。但是無法對外提供接口,可以賦值module.exports達到對外提供接口的目的。
define(function(require, exports , module){
    module.exports = {
        trim:function(){return this.replace(/(^\s*)|(\s*$)/g, "");},
        config:{"username":"foo", "age":23}
    }
});

module Object
module是一個對象,其中存儲着於當前模塊相關的一些方法和屬性。
module.id:返回模塊的標識
module.uri:返回模塊的絕對路徑。
define(function(require, exports, module){
    var module_uri = module.uri;
    //==>
http://example.com/path/to/this/file.js
});
一般情況下,如果沒有定義模塊id, 那麼module.id == module.uri,兩者完全相同。

module.dependencies Array:返回當前模塊依賴的模塊列表。
module.exports:返回當前模塊對外提供的接口對象。
注意:傳遞給factory方法的參數中exports 只是module.exports 的一個引用,只能通過exports來對外提供接口,但是module.exports可以是一個類的實例。
而且,對module.exports 賦值不能通過回調函數等方法異步執行,只能同步執行。
define(function(require, exports, module) {
// exports 是 module.exports 的一個引用 console.log(module.exports === exports); // true // 重新給 module.exports 賦值 module.exports = new SomeClass(); // exports 不再等於 module.exports console.log(module.exports === exports); // false
  //module.exports 不能異步執行
  setTimeout(function(){
    module.exports = {"username":"foo", "age":23};    //錯誤,無法對外提供接口
  }, 1000);

});

seajs.use Function 
函數:seajs.use(ids?, callback?)
作用:用在頁面上加載其他模塊。

//加載一個模塊
seajs.use("./a");

//加載一個模塊並回調
seajs.use("./a", function(a){
    a.doSomething();
});

//加載多個模塊並回調
seajs.use(["jquery","./a"], function($, a){
    $("#bt").click(function(){
        //doSomething
    });
    a.doSomething();
});
注意:seajs.use方法和document.ready()方法沒有必然關係,如果某些操作需要在document ready後才能執行操作,需要藉助jquery等依賴模塊。

seajs.cache Function
函數:seajs.cache();
可以用來查看當前頁面加載的依賴模塊列表。

seajs.resolve Function
函數:seajs.resolve(id?);
可以用來獲取依賴模塊的絕對路徑。

seajs.data Function
函數:seajs.data();
可以用來seajs的所有配置以及一些內部變量,可以用在插件開發中。

模塊標識與路徑關係
模塊標識:
模塊標識主要以小駝峯,. 或者 .. 爲主。
//在http://example.com/my/js/user.js中
define(function(require, exports, module){
    var path = require.resolve("./json");
    //==>路徑爲http://example.com/my/js/json.js
    
    var path2 = require.resolve("../json");
    //==> 路徑爲http://example.com/my/json.js
});
注意:以小駝峯開頭的模塊標識是頂級標識,以base爲根目錄加載模塊文件;以.和..開頭的模塊標識是相對標識,以當前模塊文件所在的位置爲基礎根目錄加載。

//假設base 是http://examle.com/my/js
define(function(require, exports, module){
    var path = require.resolve("json");
    //==>路徑爲http://example.com/my/js/json.js
});

注意:頁面中基於當前頁面爲根目錄加載模塊文件。

構建工具那些事
構建過程描述:
  • 提取操作
提取模塊的標識id以及模塊的其他依賴dependencies。
//a.js
define(function(require, exports, module){
    var b = require("./b");
});
經過提取操作,a.js文件會變成臨時文件:
define("xxx/1.0.0/a",["./b"],function(require, exports, module){
    var b = require("./b");
});
  • 壓縮操作
經過上面的提取操作後,構建工具就可以調用任何 JS 壓縮工具來進行壓縮了,require 參數也可以被壓縮成任意字符。相比於其他的壓縮工具,CMD模塊的構建過程增加了id和dependencies的提取過程。

爲什麼要提取模塊標識Id:

我們在模塊定義過程中,可能會合並兩個模塊定義文件,使得模塊管理更加方便和易用。
//a.js
define(function(require, exports, module){
    //todoSomething
});

//b.js
define(function(require, exports, module){
    //todoSomething
});

如果我們希望合併以上兩個文件,那麼會出現模塊定義不清楚,無法確認加載哪個模塊的問題,所以在模塊構建過程中需要提取模塊標識id。
此外,即便不合並,保持一個文件一個模塊,如果壓縮時不提取 id,那麼在 IE6-9 下也有可能會出現問題。

爲什麼要提取模塊依賴dependencies:

爲了保證壓縮文件隨意壓縮代碼,構建工具在提取id的同時,也會提取dependencies數組。這樣seajs不會再通過factory.toString()藉助於正則匹配來獲取依賴,直接可以通過factory函數的第二個參數拿到依賴數組。
注意:一旦factory的第二個參數定義了依賴數組,那麼seajs將不會使用正則匹配的方式去分析並獲取依賴,而是直接使用factory第二個參數提供的依賴數組作爲所有的依賴。




























發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章