前端框架 seajs 使用總結
阿新 • • 發佈:2020-12-15
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
path Object
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(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){ functiontrim(){ returnthis.replace(/(^\s*)|(\s*$)/g,"") } exports.trim = trim; //把內部函式暴露給其他模組 exports.config = {"username":"foo", "age":"23"};//把內部物件暴露給其他模組 }); 除了使用exports 物件對外提供介面外,還可以使用return直接對外提供介面 define(function(require, exports, module){ functiontrim(){ returnthis.replace(/(^\s*)|(\s*$)/g,"") } return { "trim":trim, "config":{"username":"foo", "age":23} } }); 如果模組中return語句是唯一的程式碼,那麼可以使用define({})簡化模組定義: define({ "trim":function(){ returnthis.replace(/(^\s*)|(\s*$)/g,"") }, "config":{"username":"foo","age":23} } ); 上面的格式可以適合定義JSONP模組。 注意:不能對exports重新賦值,這樣雖然不會影響到module.exports 。但是無法對外提供介面,可以賦值module.exports達到對外提供介面的目的。 define(function(require, exports , module){ module.exports = { trim:function(){returnthis.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第二個引數提供的依賴陣列作為所有的依賴。