2.4 關于Ext.onReady
代碼為什么寫在Ext.onReady中,而不是在body中添加一個onload事件并在onload事件中運行呢?主要原因是Ext.onReady在DOM模型加載完畢后即可進行操作,而無需像onload事件那樣,等待頁面的所有資源都加載完畢后才進行操作,尤其是在頁面有大圖片這類資源的時候。下面我們來看看Ext.onReady是如何做到這點的。
在Loader.js文件可以找到Ext.onReady的定義:
Ext.onReady = function(fn, scope, options) {Loader.onReady(fn, scope, true, options);
};
在這里調用了Loader對象的onReady方法,在Loader.js中可找到如下定義:
onReady: function(fn, scope, withDomReady, options) {var oldFn;if (withDomReady !== false && Ext.onDocumentReady) {oldFn = fn;fn = function() {Ext.onDocumentReady(oldFn, scope, options);};}fn.call(scope);
},
在上面的代碼中,因為調用時withDomReady為true,所以只需判斷Ext.onDocumentReady是否存在,如果存在,就建立一個匿名函數fn,準備執行Ext.onDocumentReady方法。最后是調用函數fn,執行Ext.onDocumentReady。
在EventManger.js中可找到Ext.onDocumentReady的定義:
onDocumentReady: function(fn, scope, options){options = options || {};var me = Ext.EventManager,readyEvent = me.readyEvent;options.single = true;readyEvent.addListener(fn, scope, options);if (Ext.isReady) {readyEvent.fire();} else if (document.readyState == 'complete') {me.fireDocReady();} else {me.bindReadyEvent();}
},
在上面的代碼中,readyEvent是Ext.util.Event的實例,options.single的作用是規定ready-Event事件只執行一次。接著將函數添加到Event實例內的監聽事件列表中,最后判斷DOM模型是否已加載完成。如果已加載完成,則調用fire方法依次執行監聽事件列表中的函數。這樣做的目的是:當存在多個onReady方法時,能保證所有的函數都能執行。如果還沒有加載完成,而document對象的readyState屬性為“complete”,表示文檔其實已經加載完成了,但是沒有設置isReady屬性為true,那么可調用fireDocReady方法,其代碼如下:
fireDocReady: function(){var me = Ext.EventManager;if (!Ext.isReady) {Ext.isReady = true;if (document.addEventListener) {document.removeEventListener('DOMContentLoaded', me.fireDocReady, false);window.removeEventListener('load', me.fireDocReady, false);} else {if (me.readyTimeout !== null) {clearTimeout(me.readyTimeout);}if (me.hasOnReadyStateChange) {document.detachEvent('onreadystatechange', me.checkReadyState);}window.detachEvent('onload', me.fireDocReady);}Ext.supports.init();me.onWindowUnload();me.readyEvent.fire();}
},
在上面的代碼中,如果isReady不是true,則將其設置為true,然后移除文檔的監聽事件。首先調用Ext.supports的init方法檢測當前運行環境的信息;然后調用onWindowUnload方法為文檔綁定unload事件,觸發后會刪除頁面的所有元素;最后再調用readyEvent的fire方法,開始執行我們定義的代碼。
如果文檔還沒有加載完成,則執行bindReadyEvent方法,其代碼如下:
bindReadyEvent: function(){var me = Ext.EventManager;if (me.hasBoundOnReady) {return;}if (document.addEventListener) {document.addEventListener('DOMContentLoaded', me.fireDocReady, false);window.addEventListener('load', me.fireDocReady, false);} else {if (!me.checkReadyState()) {document.attachEvent('onreadystatechange', me.checkReadyState);me.hasOnReadyStateChange = true;}window.attachEvent('onload', me.fireDocReady, false);}me.hasBoundOnReady = true;
},
看懂以上代碼就應該很清楚整個執行過程了。在代碼中,如果沒有在頁面中綁定監聽事件,則綁定事件,非IE瀏覽器是綁定“DOMContentLoaded”事件,IE是綁定onload事件。對于舊版本的IE,會調用checkReadyState方法檢查頁面是否準備好,因為舊版本IE只能使用替代辦法檢查DOMContentLoaded事件。事件觸發后執行fireDocReady方法。