小松的技术博客

六和敬

若今生迷局深陷,射影含沙。便许你来世袖手天下,一幕繁华。 你可愿转身落座,掌间朱砂,共我温酒煮茶。

理解DomReady(JavaScript框架学习录)

DomReady是指DOM树已经构建完成后的状态,在js中涉及到DOM相关的操作都应该在DomReady之后进行,因此判断是否处于DomReady是非常重要的,由于前端浏览器版本众多,所以兼容性还是略微复杂。本文会先列举出各色浏览器的种种表现,然后给出hack技巧

一、面临的问题:

  1. firfox<3.6的版本没有document.readystate
  2. IE低版本不支持DOMContentLoaded事件
  3. 脚本可能是动态加载的,因此有可能加载时就已经处于DomReady了,这个时候无法触发DOMContentLoaded事件,因此还需要readyState的协助

二、解决方法

  1. FF没有document.readystate的问题在labjs中有兼容方案,如下:

    (function(addEvent,domLoaded,handler){
        if (document.readyState == null && document[addEvent]){
            document.readyState = "loading";
            document[addEvent](domLoaded,handler = function(){
                document.removeEventListener(domLoaded,handler,false);
                document.readyState = "complete";
            },false);
        }
    })("addEventListener","DOMContentLoaded");
    
  2. IE低版本可以使用Diego Perini发明的著名hack!

    //来源:http://javascript.nwbox.com/IEContentLoaded/
    function IEContentLoaded (w, fn) {
        var d = w.document, done = false,
        // only fire once
        init = function () {
            if (!done) {
                done = true;
                fn();
            }
        };
        // polling for no errors
        (function () {
            try {
                // throws errors until after ondocumentready
                d.documentElement.doScroll('left');
            } catch (e) {
                setTimeout(arguments.callee, 50);
                return;
            }
            // no errors, fire
            init();
        })();
        // trying to always fire before onload
        d.onreadystatechange = function() {
            if (d.readyState == 'complete') {
                d.onreadystatechange = null;
                init();
            }
        };
    }
    

三、一个简单的完整实现

下面是参照司徒正美的实现给出的一个简单实现

function domReady(fn){
    var doc = document;
    var w3c = doc.dispatchEvent;//IE9及以上和标准浏览器支持
    var html = doc.documentElement;
    var readyState;
    if(!doc.readyState){
        readyState = doc.readyState = doc.body?'complete':'loading';
    }
    var done = false;
    var callback = function(){
        if(!done){
            done = true;
            fn();
        }
    }
    if(doc.readyState === 'complete'){//如果已经是complete,直接触发回调
        callback();
    }else{//添加绑定事件
        if(w3c){
            doc.addEventListener('DOMContentLoaded',function(){
                callback()
                if(readyState){//ff<3.6
                    doc.readyState = "complete";
                }
            });
        }else{//IE低版本
            doc.onreadystatechange = function(){
                if(doc.readyState === 'complete'){
                    callback();
                }
            }
        }
    }

    function doScrollCheck(){
        try{
            html.doScroll("left");
            callback();
        }catch(e){
            setTimeout(doScrollCheck,50);
        }
    }
}
←支付宝← →微信 →
comments powered by Disqus