关于dom ready的那点事儿

       终于学生生涯最后一个寒假也就这么的过完了,昨天回到川大,休息了一天,今天正式开始做毕设了。

       晚上看完 年代秀,不想码代码,所以就把寒假在家学习的一些分享出来。

       之前在学校,由于项目一般工期都狠紧张,所以频繁使用Jquery,后来Jquery用多了,反而原生的JS感觉很陌生了。寒假的时候,顺便看了看kissy,tangram,然后自己慢慢开始写一个库,通过编写这种库来学习JS。

        在原生的JS中,使用window.onload可以实现当文档载入之后执行一段代码,但是window.onload只能执行一次,而且它必须要等到包括图片等元素全部载入之后才能执行,很不友好,所以各个JS的库都有ready这个函数,如Jquery中,$(document).ready,这个函数函数可以执行多次,并且当DOM结构绘制完毕之后就会执行,不必等到所有元素全部载入,所以它的执行要比window.onload要早。

        由于我上学期面试百度前端的时候被面试官无情的刷掉了,但是他推荐了tangram给我,所以这个寒假看的最多的就是tangram,希望借此提高自己JS水平。

        PS:说起这个,还需要对tohilary说声sorry了,之前你在oschina上和我交流说希望把toper放到github上面,我答应你寒假去修改一下toper,结果我寒假去搞JS去了,由于我是单核的,并发能力不强,所以基本上没有做这个。

        我看了一下tangram关于ready的实现(baidu.dom.ready),基本上和Jquery的实现相同。tangram的实现代码如下:


(function() {

    var ready = baidu.dom.ready = function() {
        var readyBound = false,
            readyList = [],
            DOMContentLoaded;

        if (document.addEventListener) {
            DOMContentLoaded = function() {
                document.removeEventListener('DOMContentLoaded', DOMContentLoaded, false);
                ready();
            };

        } else if (document.attachEvent) {
            DOMContentLoaded = function() {
                if (document.readyState === 'complete') {
                    document.detachEvent('onreadystatechange', DOMContentLoaded);
                    ready();
                }
            };
        }
        /**
         * @private
         */
        function ready() {
            if (!ready.isReady) {
                ready.isReady = true;
                for (var i = 0, j = readyList.length; i < j; i++) {
                    readyList[i]();
                }
            }
        }
        /**
         * @private
         */
        function doScrollCheck(){
            try {
                document.documentElement.doScroll("left");
            } catch(e) {
                setTimeout( doScrollCheck, 1 );
                return;
            }   
            ready();
        }
        /**
         * @private
         */
        function bindReady() {
            if (readyBound) {
                return;
            }
            readyBound = true;

            if (document.readyState === 'complete') {
                ready.isReady = true;
            } else {
                if (document.addEventListener) {
                    document.addEventListener('DOMContentLoaded', DOMContentLoaded, false);
                    window.addEventListener('load', ready, false);
                } else if (document.attachEvent) {
                    document.attachEvent('onreadystatechange', DOMContentLoaded);
                    window.attachEvent('onload', ready);

                    var toplevel = false;

                    try {
                        toplevel = window.frameElement == null;
                    } catch (e) {}

                    if (document.documentElement.doScroll && toplevel) {
                        doScrollCheck();
                    }
                }
            }
        }
        bindReady();

        return function(callback) {
            ready.isReady ? callback() : readyList.push(callback);
        };
    }();

    ready.isReady = false;
})();
        代码不是很多,实现原理也并不复杂,(function(){})()这种方式可以自动执行function里面的代码,并且保证这些代码不被其他代码污染,我很喜欢这种写法。


        ready的基本原理就是当这段代码执行的时候,它会添加一个事件监听器来监听是否文档树已经被载入完成,如果没有完成,则把ready的回调函数加入到等待的队列,如果载入完成,首先移除事件监听器,并且执行队列里面的所有回调函数。

       事件监听则按照是否是IE而不同,IE使用atachEvent添加事件监听器,detchEvent移除事件监听器,并且这里的事件都是以on开头,如onXXX,而W3C的浏览器使用addEventListener和removeEventListener来添加或移除事件监听器。

       PS:IE只支持冒泡,而W3C的支持捕获和冒泡。

       readyBound用来判定是否已经 绑定了事件,isReady用来判定是否DOM已经载入完成,readyList是一个队列,用来存储在DOM载入完成前调用ready的回调函数。

       在firefox,opera和webkit内核的浏览器(如chrome)中,它支持DOMContentLoaded这个事件,所以可以直接使用DOMContentLoaded来判定,非常简单;在IE中,可以利用IE的一个trick,可以点击这里查看详细内容,基本原理就是利用IE在文档载入完成前执行document.documentElement.doScroll("left")会出错,通过try catch来不断测试,一旦它不出错了,即文档载入完成了,如:


try {
		document.documentElement.doScroll('left');
	} catch (e) {
		setTimeout(arguments.callee, 50);
		return;
	}
      而如果以上措施还不行,就使用window.onload,这样可以确保载入完成后可以执行回调。


      window.frameElement这个可以来判定是否是frame这种情况,如果是那么会返回对象,否则会返回undefined。

      好了,就说这么多吧!!

你可能感兴趣的:(js,dom,学习,ready,明庭令)