• IE模拟addDOMLoadEvent和jQuery的ready实现


    由于 window.onload 事件需要在页面所有内容(包括图片等)加载完后,才执行,但往往我们更希望在 DOM 一加载完就执行脚本。其实在现在大部分主流浏览器上(Firefox 3+,Opera 9+,Safari 3+,Chrome 2+)都提供了这一事件方法:addDOMLoadEvent

    document.addEventListener("DOMContentLoaded", init,false);

    dom渲染完成,doScroll方法从不能执行到可执行,这样我们在IE中,利用 doScroll()方法来模拟 addDOMLoadEvent 事件,现在主流的 JavaScript 框架(JQuery、YUI等)基本都采用的这一解决方案。

    /*
     *
     * IEContentLoaded.js
     *
     * Author: Diego Perini (diego.perini at gmail.com) NWBOX S.r.l.
     * Summary: DOMContentLoaded emulation for IE browsers
     * Updated: 05/10/2007
     * License: GPL/CC
     * Version: TBD
     *
     */
    // @w    window对象的引用
    // @fn   回调函数
    function IEContentLoaded(w, fn) {
        var d = w.document,
        done = false,
        // 只执行一次
        init = function() {
            if (!done) {
                done = true;
                fn();
            }
        }; // 循环执行,直到无错误
        (function() {
            try { // 一直抛出错误,直到dom渲染结束
                d.documentElement.doScroll('left');
            } catch(e) {
                setTimeout(arguments.callee, 50);
                return;
            } // 没有错误,执行函数
            init();
        })(); // 双重保险,绑定事件
        d.onreadystatechange = function() {
            if (d.readyState == 'complete') {
                d.onreadystatechange = null;
                init();
            }
        };
    }

    参考于 http://www.planabc.net/2009/07/30/adddomloadevent/

    jQuery1.4.4中ready实现

    jQuery.fn = jQuery.prototype = {
        // ...
        ready: function( fn ) {
                // 绑定上监听事件
                jQuery.bindReady();
    
                // 如果dom已经渲染
                if ( jQuery.isReady ) {
                    // 立即执行
                    fn.call( document, jQuery );
    
                // 否则,保存到缓冲队列,等上面的监听事件触发时,再全部执行
                } else if ( readyList ) {
                    // 将回调增加到队列中
                    readyList.push( fn );
                }
    
                return this;
            },
        // ...
    };    
    jQuery.extend({
    // ...
        // dom是否渲染完成标志
        isReady: false,
    
        // 一个计数器,用于跟踪在ready事件出发前的等待次数
        // 预留,支持于更高版本jQuery提供的ready等待方法
        readyWait: 1,
        
        // 文档加载完毕句柄,dom渲染完成后执行
        ready: function( wait ) {
            // A third-party is pushing the ready event forwards
            if ( wait === true ) {
                jQuery.readyWait--;
            }
    
            // Make sure that the DOM is not already loaded
            if ( !jQuery.readyWait || (wait !== true && !jQuery.isReady) ) {
                // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
                // 确保body元素存在,这个操作是防止IE的bug
                if ( !document.body ) {
                    return setTimeout( jQuery.ready, 1 );
                }
    
                // dom渲染完成标志设置为true
                jQuery.isReady = true;
    
                // If a normal DOM Ready event fired, decrement, and wait if need be
                if ( wait !== true && --jQuery.readyWait > 0 ) {
                    return;
                }
    
                // 绑定的渲染完成后的执行函数
                if ( readyList ) {
                    // 全部执行
                    var fn,
                        i = 0,
                        ready = readyList;
    
                    // 重置
                    readyList = null;
    
                    while ( (fn = ready[ i++ ]) ) {
                        fn.call( document, jQuery );
                    }
    
                    // 触发所有ready事件
                    if ( jQuery.fn.trigger ) {
                        jQuery( document ).trigger( "ready" ).unbind( "ready" );
                    }
                }
            }
        },
        // 初始化readyList事件处理函数队列
        // 兼容不同浏览对绑定事件的区别
        bindReady: function() {
            if ( readyBound ) {
                return;
            }
    
            readyBound = true;
    
            // $(document).ready()的嵌套调用时
            // readyState: "uninitalized"、"loading"、"interactive"、"complete" 、"loaded"
            if ( document.readyState === "complete" ) {
                // 让它异步执行,使这个ready能延迟
                return setTimeout( jQuery.ready, 1 );
            }
    
            // Mozilla, Opera and webkit 
            // 兼容事件,通过检测浏览器的功能特性,而非嗅探浏览器
            if ( document.addEventListener ) {
                // 使用事件回调函数
                document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
                
                // 绑定回调到load,使之能一定执行
                window.addEventListener( "load", jQuery.ready, false );
    
            // IE
            } else if ( document.attachEvent ) {
                // 确保在load之前触发onreadystatechange,
                // 针对iframe情况,可能有延迟
                document.attachEvent("onreadystatechange", DOMContentLoaded);
                
                // 绑定回调到一定执行能load事件
                window.attachEvent( "onload", jQuery.ready );
    
                // 如果是IE且非iframe情况下
                // 持续的检查,看看文档是否已准备
                var toplevel = false;
    
                try {
                    toplevel = window.frameElement == null;
                } catch(e) {}
    
                if ( document.documentElement.doScroll && toplevel ) {
                    doScrollCheck();
                }
            }
        },
    
    // ...
    });    
    if ( document.addEventListener ) {
        DOMContentLoaded = function() {
            document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
            jQuery.ready();
        };
    
    } else if ( document.attachEvent ) {
        DOMContentLoaded = function() {
            // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
            if ( document.readyState === "complete" ) {
                document.detachEvent( "onreadystatechange", DOMContentLoaded );
                jQuery.ready();
            }
        };
    }
    // IE循环检查dom是否渲染完毕
    function doScrollCheck() {
        if ( jQuery.isReady ) {
            return;
        }
    
        try {
            // If IE is used, use the trick by Diego Perini
            // http://javascript.nwbox.com/IEContentLoaded/
            document.documentElement.doScroll("left");
        } catch(e) {
            setTimeout( doScrollCheck, 1 );
            return;
        }
    
        // 执行在等待的函数
        jQuery.ready();
    }

     将jQuery的ready方法剥离出,提取为函数ready及测试例子

    <!DOCTYPE html>
    <html>
    <head>
        <title></title>
        <meta http-equiv="content-type" content="text/html;charset=utf-8">
        <script type="text/javascript">
            (function(window, undefined) {
                var readyList = [],
                        isReady = 0,
                        readyBound = false,
                        init,
                        bindReady,
                        readyWait = 1;
                init = function(wait) { // A third-party is pushing the ready event forwards
                    if (wait === true) {
                        readyWait--;
                    } // Make sure that the DOM is not already loaded
                    if (!readyWait || (wait !== true && !isReady)) { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
                        // 确保body元素存在,这个操作是防止IE的bug
                        if (!document.body) {
                            return setTimeout(init, 1);
                        } // dom渲染完成标志设置为true
                        isReady = true; // If a normal DOM Ready event fired, decrement, and wait if need be
                        if (wait !== true && --readyWait > 0) {
                            return;
                        } // 绑定的渲染完成后的执行函数
                        if (readyList) { // 全部执行
                            var fn, i = 0,
                                    ready = readyList; // 重置
                            readyList = null;
                            while ((fn = ready[i++])) {
                                fn.call(document);
                            }
                        }
                    }
                }; // 初始化readyList事件处理函数队列
                // 兼容不同浏览对绑定事件的区别
                bindReady = function() {
                    if (readyBound) {
                        return;
                    }
                    readyBound = true; // $(document).ready()的嵌套调用时
                    // readyState: "uninitalized"、"loading"、"interactive"、"complete" 、"loaded"
                    if (document.readyState === "complete") { // 让它异步执行,使这个ready能延迟
                        return setTimeout(init, 1);
                    } // Mozilla, Opera and webkit
                    // 兼容事件,通过检测浏览器的功能特性,而非嗅探浏览器
                    if (document.addEventListener) { // 使用事件回调函数
                        document.addEventListener("DOMContentLoaded",
                                function() {
                                    document.removeEventListener("DOMContentLoaded", arguments.callee, false);
                                    init();
                                },
                                false); // 绑定回调到load,使之能一定执行
                        window.addEventListener("load", init, false); // IE
                    } else if (document.attachEvent) { // 确保在load之前触发onreadystatechange,
                        // 针对iframe情况,可能有延迟
                        document.attachEvent("onreadystatechange",
                                function() { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
                                    if (document.readyState === "complete") {
                                        document.detachEvent("onreadystatechange", arguments.callee);
                                        init();
                                    }
                                }); // 绑定回调到一定执行能load事件
                        window.attachEvent("onload", init); // 如果是IE且非iframe情况下
                        // 持续的检查,看看文档是否已准备
                        var toplevel = false;
                        try {
                            toplevel = window.frameElement == null;
                        } catch(e) {}
                        (function() {
                            if (document.documentElement.doScroll && toplevel) {
                                if (isReady) {
                                    return;
                                }
                                try { // If IE is used, use the trick by Diego Perini
                                    // http://javascript.nwbox.com/IEContentLoaded/
                                    document.documentElement.doScroll("left");
                                } catch(e) {
                                    setTimeout(arguments.callee, 1);
                                    return;
                                } // 执行在等待的函数
                                init();
                            }
                        })();
                    }
                };
                window.ready = function(fn) { // 绑定上监听事件
                    bindReady(); // 如果dom已经渲染
                    if (isReady) { // 立即执行
                        fn.call(document); // 否则,保存到缓冲队列,等上面的监听事件触发时,再全部执行
                    } else if (readyList) { // 将回调增加到队列中
                        readyList.push(fn);
                    }
                };
            })(window);
            ready(function(){
                var inp = document.getElementById('inp');
                console.log(inp.nodeName);
            });
            ready(function(){
                console.log('second ready');
                ready(function(){
                    console.log('in the second ready')
                })
            })
        </script>
    </head>
    <body>
      <input type="text" id="inp"/>
    </body>
    </html>
            <script type="text/javascript">
                ready(function(){
                    console.log('third ready');
                });
            </script>

     平时测试简单方法

     

    // 来源于 http://www.planabc.net/2011/05/26/domready_function/
    function domReady(fn) {
        // "uninitalized"、"loading"、"interactive"、"complete" 、"loaded"
        /in/.test(document.readyState) ? window.setTimeout(function() { domReady(fn); }, 10) : fn();
    }
    有任何问题,欢迎留言交流。 注意:已解决的问题,会在整理后删除掉。

    *******站在巨人的肩膀上

  • 相关阅读:
    Eclipse中支持js提示
    数据库命名规则
    JavaWeb 命名规则
    Ajax&json
    js中,var 修饰变量名和不修饰的区别
    javaScript知识点
    Bootstrap 栅格系统
    文本框如果不输入任何内容提交过后是一个空字符串还是null
    根据汇总数量依次扣减的SQL新语法
    asp.net中使用forms验证
  • 原文地址:https://www.cnblogs.com/sprying/p/3093957.html
Copyright © 2020-2023  润新知