且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

《Ext JS权威指南》——2.4节关于Ext.onReady

更新时间:2022-09-24 12:09:26

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方法。