文档章节

关于dom ready的那点事儿

阳光test
 阳光test
发布于 2013/02/25 22:42
字数 1060
阅读 574
收藏 4

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

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

       之前在学校,由于项目一般工期都狠紧张,所以频繁使用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。

      好了,就说这么多吧!!

© 著作权归作者所有

阳光test

阳光test

粉丝 542
博文 71
码字总数 91741
作品 1
杭州
程序员
私信 提问
加载中

评论(1)

开源无憾
开源无憾
这个我喜欢,很详细。谢谢分享!
我的友情链接

新浪硬件 3GP手机视频下载 btchina seven 陈皓的个人专栏 《Java程序员,上班那点事儿》的那点事儿 李天平 Java究竟怎么玩 豆子空间 子 孑 xql888 ITMOV旗舰 Simon Xiao 肖舸的blog 我的数据...

leizhimin
2017/11/22
0
0
TryjQuery:jQuery官方推出的教学视频『更新至最后一集』

在今年2月15日,jQuery 官方推出“学习中心”站点后,3月底 jQuery 官方联合 Code School 又推出了一个学习资源 TryjQuery,其中包括14个视频、71个交互式挑战。 3月28日我们在@程序员的那些...

2013/07/27
0
0
【Maven 那点事儿】中的图是拿什么画的呀

@黄勇 你好,想跟你请教个问题: 【Maven 那点事儿】中的图http://my.oschina.net/huangyong/blog/194583是拿什么画的呀?

bopjiang
2014/12/12
181
0
System.IO系列:局域网内多线程使用命名管道在进程之间通信实例

有关管道的基本用法请看System.IO之使用管道在进程间通信 (System.IO.Pipes使用)。 本文介绍命名管道使用实例,文中例子是几个客户端都通过一台服务器获得新生成的int类型id。 服务器端功能...

长平狐
2012/06/08
266
0
使用 CXF 开发 REST 客户端调用问题

@黄勇 你好,想跟你请教个问题: Web Service 那点事儿(4)—— 使用 CXF 开发 REST 客户端调用出现异常: javax.ws.rs.NotAuthorizedException: HTTP 401 Unauthorized 好像是没有授权认证!...

simplehpt
2015/02/13
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

001-docker的基础概念

安装 yum install docker;systemctl status docker 我们启动docker的时候,docker会帮我们创建一个docker 0的网桥 docker 基础命令 查看当前镜像 docker images 搜索镜像 docker search 执行...

侠客行之石头
50分钟前
5
0
OSChina 周六乱弹 —— 不要在领导修风扇的时候打开电扇

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @巴拉迪维 :《Whats Up》 主唱妹子 Lina Perry 的嗓音实在太有力了,收放自如的自信才能唱出这么优秀的歌吧!#今日歌曲推荐# 《Whats Up》-...

小小编辑
今天
26
2
SpringBoot集成Elasticsearch并进行增删改查操作

一、创建工程 使用IntelliJ创建SpringBoot工程 SpringBoot版本为2.0.4 ElasticSearch为5.6.10 删掉蓝框中的文件(如上) 最后我们的目录结构(如下) 下面pom文件主要修改的是把spring boot从Int...

一字见心
今天
5
0
聊聊rocketmq的TransientStorePool

序 本文主要研究一下rocketmq的TransientStorePool TransientStorePool rocketmq-all-4.6.0-source-release/store/src/main/java/org/apache/rocketmq/store/TransientStorePool.java publi......

go4it
昨天
6
0
笔记

场外借贷, 质押 ,托管, 永续合约. 场外借贷,n签合同. 新功能 证券交易组负责中信证券机构及个人投资交易相关系统,服务机构及个人投资客户, 涉及到两融、期权、 期货、做市等境内境外创新业...

MtrS
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部