Web UI - Javascript之DOM Ready

最近终于稍微适应了工作环境,终于可以让自己缓口气。于是决定要写点东西,算是督促、记录和提升自己的学习。代码的世界,你不轮它,以后就会被它轮。这个系列尽量保持在一周或两周更一篇,目标是在创造内容的时候更深刻的理解和提升自己所学的知识, 本质上,接触Javascript编程之美,我转到前端工作,其实就是因为非常喜欢和好奇Javascript(当然,也是享受频繁的用代码和用户交互的感觉)。

什么是DOM Ready

还记得刚学习Javascript的时候,老师就一直各种强调教导告诉你说js的代码一定要写到window.onload里面,如下代码:

1 window.onload=function()
2 {
3     //registered in onload
4     document.getElementById(‘demo‘).innerHTML=‘hello world‘;
5 }

window.onload

  包括各种古老的书籍中都告诉你说为了保证js能够正确运行(因为js大部分都是频繁的操作DOM),应该把代码写在onload中,而window.onload表示着web页面中所有的元素都已经加载完毕,保证了所有的DOM元素都是可用的。然而,DOM元素是丰富多彩的, 例如:img。当然一个img请求一张图片,而这张图片很大、路径错误等原因会造成请求一直下不来,如果你的页面上有这样一张图片,那么window.onload将会一直等待这张图片的加载,直到图片请求已经下来了或确认图片请求异常。这是一个可怕的过程,如果一张 图片请求了10s,那么你的用户在电脑面前面对着浏览器那个正在加载的圆圈的时候,很有可能关掉你的页面。

  这是一个很简单的case:onload太慢了。小伙鸡如果你现在竟然还在用着window.onload那就真的图样图森破了。

DOMContentLoaded

  感觉到onload太慢了,firefox为DOM纳入了一个全新的事件,叫做DOMContentLoaded,这也就是我们后来所说的DOM Ready。DOM Ready和onload不同之处在于:onload等待页面所有元素加载完毕才会执行,而DOM Ready,则 是在DOM树构建完毕即执行。这一过程可以这么形容:onload的时候页面已经呈现,而DOM Ready完毕的时候甚至用户都还没有看见页面。我们可以更快的处理一些事情,而不是等到onload之后。 而这一事件,逐渐的被广大浏览器纳入,除了那些古老的IE浏览器。

现在的前端js框架类库,例如jQuery、Zepto、YUI、mass没有个DOM Ready都不好意思称自己为库、框架。刚开始学习jQuery的时候,就对这个DOM Ready非常的感兴趣,当时因为自己的境界还停留在学习jQuery的时候,所以只能远远观望。当驾驭了jQuery的时候,我们就应该透过现象看本质——一窥jQuery源码,探索里面的秘密。

  其实DOM Ready,实现上非常简单,就是注册个DOM Ready的事件,但是低版本的IE(IE678)要么没有DOMContentLoaded事件,要么就是DOMContentLoaded的实现上有bug。

  所以,我们自己动手来实现DOM Ready吧。

首先,w3c的实现,用w3c规范注册DOMContentLoaded事件,同时针对IE8 hack,一个简单的DOM Ready示例如下:

 1     //将一个函数注册到DOM Ready
 2     function $(fn) {
 3         if (document.addEventListener)//w3c browser
 4             document.addEventListener("DOMContentLoaded", fn, false);
 5         else if (document.attachEvent)//ie8+ browser
 6             document.attachEvent("onreadystatechange", fn);
 7     }
 8
 9
10     //注册一个DOM Ready事件,是不是和jQuery很像?
11     $(function () {
12         console.log(‘hello world!‘);
13     });

DOMContentLoaded

我们不能忘记万恶的IE

  不要忘记,在你编写了一段在现代浏览器中运行起来各种没问题so beautiful,正觉得自己碉堡了的时候,你打开了IE,然后眼睁睁的看着它对你的精神各种侮辱xxoo的那种感觉吧。没错,万恶的IE

  上面的代码中,我们针对IE进行readystatechange进行绑定,IE为DOM的一部分提供readystatechange事件。然而,IE678,在页面中有iframe的情况下,DOM Ready的加载就会被影响,没错,它在等待iframe加载完毕才会执行readystatechange事件。

为此,我做了一番模拟,如下HTML:

 1 <!DOCTYPE html>
 2 <html xmlns="http://www.w3.org/1999/xhtml">
 3 <head>
 4     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 5     <title>IE下readystatechange事件测试 - linkFly</title>
 6     <script type="text/javascript">
 7
 8         //开始记录时间
 9         var date = new Date();
10         +function () {
11             //注册readystatechange函数
12             document.attachEvent("onreadystatechange", function () {
13                 //跟踪这个函数执行的时间
14                 document.getElementById(‘demo‘).innerHTML = Math.floor((new Date()).getTime() - date.getTime()) / 1000;
15             });
16         }();
17     </script>
18 </head>
19 <body>
20     <div id="demo"></div>
21     <!--这里显示readystatechange时间差-->
22     <iframe src="https://github.com/" height="20" width="800"></iframe>
23     <div id="end"></div>
24     <!--这里是DOM Ready时间差-->
25 </body>
26 <script type="text/javascript">
27     //js写在这个位置,DOM可以说已经构建完毕,跟踪执行时间
28     document.getElementById(‘end‘).innerHTML = Math.floor((new Date()).getTime() - date.getTime()) / 1000;
29 </script>
30 </html>

readystatechange

  然后,就发生了一些有意思的事情,如下图:

  iframe里面特意链到Github,所以访问起来很慢(天朝,你懂的...)。可以看见,下面的DOM Ready的代码执行的很快,但是上面的readystatechange,ie8下我们忍了,但是这ie6、7是个神马情况???12s后才执行,简直就是坑爹夫斯基啊!!!!!这玩意儿尼玛不靠谱啊。

  我用写好的DOM Ready进行测试,效果如下:

  这速度,这效果,so beautiful啊...

  总结起来就是,有iframe的页面,readystatechange并不靠谱,那么我们需要单独处理一下这个情况,针对这一情况,最著名的莫过于Diego Perini发现的hack:

 1 +function(fn)//ie678检测iframe的DOMReady
 2 {
 3     try {
 4         //IE下页面DOM没有加载完成,调用doScroll会报错
 5         document.documentElement.doScroll("left");
 6         //没有报错,证明DOM已经加载完毕,执行DOM Ready里需要执行事件
 7         fn();
 8     } catch (e) {
 9         //重复调用自己
10         setTimeout(arguments.callee, 1);
11     }
12 }(function(){
13     document.getElementById(‘demo‘).innerHTML=‘hello world!‘;
14 });

ie678hack

  好的,现在我们也已经知道了怎么解决IE下的问题,那么现在,我们就应该把这两段代码合并,封装一个DOMReady库,下次使用我们直接就可以用了。没错,DOM Ready其实就这点东西,是不是so easy啊。那么我们准备封装类库吧。

  让我们想想,jQuery的DOM Ready是不是可以多个事件绑定到DOM Ready?那么我们也来实现这样的效果,检测DOM Ready,然后执行事件集合,在Js,就用数组来实现。

  其实代码上很大一部分参照了jQuery源码,但是jQuery解耦解的实在丧心病狂,所以一个DOM Ready跳转了不下30多个方法,当然,侦听DOM Ready的代码并不是很繁琐,jQuery主要在DOM Ready的将要执行的事件上进行了良好的解耦和封装。 好了话不多说,上源码:

源码

  Javascript源码:  

 1 /*!
 2 * by - linkfly
 3 * cnblogs - http://www.cnblogs.com/silin6/
 4 */
 5 (function (window, undefined) {
 6     /*
 7     *                                   checkReady
 8     * event model:ready ->> bindReady ->>
 9     *                                   ie(iframe):doScrollCheck ->> checkReady
10     */
11     var readyList = [],                     //DOM Ready执行的数组
12         document = window.document,
13         DOMContentLoaded,                   //DOMReady事件
14         isReady = false,                    //DOM是否准备完毕
15         triggerReady = function () {        //触发ready事件
16             while (readyList.length) {
17                 readyList[0].call(window); //指定上下文
18                 readyList.shift();
19             }
20         };
21     //ready执行方法,检测需要的环境是否已经准备好,它是DOM Ready最后一道关卡
22     var checkReady = function () {
23         if (!document.body) { return setTimeout(checkReady, 1); }
24         isReady = true; //标识完成
25         triggerReady();
26     },
27     //本来还想使用一个wait数组表示当前正在等待执行的数据,但是因为下面用的addEventListener和attachEvent,所以直接让js Event维护即可
28      bindReady = function () {         //绑定ready
29          //body必须存在
30          //如果DOM Ready,则直接触发,Firefox3.6之前并没有readyState,考虑市场因素抛弃这部分兼容
31          if (document.readyState === ‘complete‘ || isReady) { return setTimeout(triggerReady, 1); }
32          if (document.addEventListener) {//w3c
33              document.addEventListener("DOMContentLoaded", DOMContentLoaded, false);
34              //如果没有赶上DOM Ready,则监听load
35              window.addEventListener("load", checkReady, false);
36          } else if (document.attachEvent) {//ie
37              document.attachEvent("onreadystatechange", DOMContentLoaded);
38              window.attachEvent("onload", checkReady);
39              //ie下多iframe
40              var toplevel = false;
41              try {
42                  toplevel = window.frameElement == null;
43              } catch (e) { }
44              if (document.documentElement.doScroll && toplevel) {
45                  doScrollCheck();
46              }
47          }
48      },
49     doScrollCheck = function () {                  //ie678检测iframe的DOMReady
50         try {
51             //IE下页面DOM没有加载完成,调用doScroll会报错
52             document.documentElement.doScroll("left");
53             checkReady();
54         } catch (e) {
55             setTimeout(doScrollCheck, 1);
56         }
57     },
58     ready = function (fn) {                 //DOM Ready
59         //判定fn有效性代码略过...
60         readyList.push(fn);
61         bindReady();
62     };
63     ~function () {
64         if (document.addEventListener) {
65             DOMContentLoaded = function () {
66                 document.removeEventListener("DOMContentLoaded", DOMContentLoaded, false);
67                 checkReady();
68             };
69         } else if (document.attachEvent) {
70             DOMContentLoaded = function () {
71                 if (document.readyState === "complete") {
72                     document.detachEvent("onreadystatechange", DOMContentLoaded);
73                     checkReady();
74                 }
75             };
76         }
77     }();
78     window.$ = window.ready = ready;
79 })(window);

DOM Ready

  HTML源码:

 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 2 <html xmlns="http://www.w3.org/1999/xhtml">
 3 <head>
 4     <title>测试DOM Ready - linkFly</title>
 5     <!--<script src="jQuery/jquery-1.7.2.js" type="text/javascript"></script>-->
 6     <script src="DOMReady.js" type="text/javascript"></script>
 7     <script type="text/javascript">
 8         //http://localhost:2969/test.html
 9         $(function () {
10             document.getElementById(‘test‘).innerHTML += ‘<p>顶部:完毕</p>‘;
11             alert(window.frames[0].document.firstChild.innerHTML);
12         });
13     </script>
14     <style type="text/css">
15         img { height: 20px; width: 20px; }
16     </style>
17 </head>
18 <body>
19     <div id="test">
20     </div>
21     <div id="test2">
22     </div>
23     <div id="test3">
24     </div>
25     <img src="http://c.s-microsoft.com/en-us/CMSImages/MS_FavMoments_End_1600x540_EN_US.jpg?version=10582f1d-db23-3040-9cf3-3ec93ece226d&h=0"
26         alt="" />
27     <img src="http://c.s-microsoft.com/en-us/CMSImages/MS_FavMoments_End_1600x540_EN_US.jpg?version=10582f1d-db23-3040-9cf3-3ec93ece226d&h=1"
28         alt="" />
29     <img src="http://c.s-microsoft.com/en-us/CMSImages/MS_FavMoments_End_1600x540_EN_US.jpg?version=10582f1d-db23-3040-9cf3-3ec93ece226d&h=2"
30         alt="" />
31     <img src="http://c.s-microsoft.com/en-us/CMSImages/MS_FavMoments_End_1600x540_EN_US.jpg?version=10582f1d-db23-3040-9cf3-3ec93ece226d&h=3"
32         alt="" />
33     <img src="http://c.s-microsoft.com/en-us/CMSImages/MS_FavMoments_End_1600x540_EN_US.jpg?version=10582f1d-db23-3040-9cf3-3ec93ece226d&h=4"
34         alt="" />
35     <img src="http://c.s-microsoft.com/en-us/CMSImages/MS_FavMoments_End_1600x540_EN_US.jpg?version=10582f1d-db23-3040-9cf3-3ec93ece226d&h=5"
36         alt="" />
37     <img src="http://c.s-microsoft.com/en-us/CMSImages/MS_FavMoments_End_1600x540_EN_US.jpg?version=10582f1d-db23-3040-9cf3-3ec93ece226d&h=6"
38         alt="" />
39     <img src="http://c.s-microsoft.com/en-us/CMSImages/MS_FavMoments_End_1600x540_EN_US.jpg?version=10582f1d-db23-3040-9cf3-3ec93ece226d&h=7"
40         alt="" />
41     <img src="http://c.s-microsoft.com/en-us/CMSImages/MS_FavMoments_End_1600x540_EN_US.jpg?version=10582f1d-db23-3040-9cf3-3ec93ece226d&h=8"
42         alt="" />
43     <img src="http://c.s-microsoft.com/en-us/CMSImages/MS_FavMoments_End_1600x540_EN_US.jpg?version=10582f1d-db23-3040-9cf3-3ec93ece226d&h=9"
44         alt="" />
45     <iframe src="https://github.com/" height="200" width="800"></iframe>
46     <!--测试iframe跨域-->
47 </body>
48 <script type="text/javascript">
49     $(function () {
50         document.getElementById(‘test2‘).innerHTML += ‘<p>底部:完毕</p>‘;
51     });
52 </script>
53 </html>

HTML Demo

  到了这里,是不是有点觉得onload就应该被舍弃呢?其实不然,onload也不是一无是处,例如chrome不同的图片渲染引擎,造成了无法在DOM中处理图片,当然这也是合理的,DOM树中或许图片都还没有下载呢,遇见过这样的情况,只能在onload中对图片进行处理。  

源码下载地址

作者:linkFly

原文:http://www.cnblogs.com/silin6/p/DOMReady.html

出处:www.cnblogs.com/silin6/

声明:嘿!你都拷走上面那么一大段了,我觉得你应该也不介意顺便拷走这一小段,希望你能够在每一次的引用中都保留这一段声明,尊重作者的辛勤劳动成果,本文与博客园共享。

Web UI - Javascript之DOM Ready

时间: 2024-10-29 04:37:35

Web UI - Javascript之DOM Ready的相关文章

【JavaScript】谈谈Google Polymer以及Web UI框架的未来

摘要:开发者Axel Rauschmayer在自己的博客上详解了Google Polymer的设计理念与组成架构,深得Polymer开发者的认同.他认为Polymer这样高互操作性的设计才应该是Web开发的未来. 虽然今年的Google I/O也已结束,但会上揭晓的新技术.新工具仍然让开发者兴奋不已.其中Web开发方面尤以Ploymer和Web Components为重. Polymer由加盟Google的原Palm webOS开发团队打造,是一套以“一切皆组件.最少化代码量.最少框架限制”为设

10个优秀的JavaScript Web UI库/框架推荐

在进行Web开发时,并非所有的库都适合你的项目,但你仍需要收藏一些Web UI设计相关的库或框架,以在你需要的时候,加快你的开发效率. 本文为你带来10款非常优秀的基于JavaScript的Web UI设计资源. 1.  XUI:JavaScript微型框架 这是一个“轻量级.非常简单.微型.超级模块化”的JavaScript框架,用于创建移动Web应用.该框架如此轻量级的原因是一些与浏览器兼容相关的代码被剥离. 2.  iUI:iPhone UI 框架 该框架由JavaScript库.CSS和

Python之路day13 web 前端(JavaScript,DOM操作)

参考链接:http://www.cnblogs.com/wupeiqi/articles/5433893.html day13 1. CSS示例 2. JavaScript 3. DOM操作 上节内容回顾: 1. HTML标签 html/head/body/ input div,span a p br span table > tr行 th表头列 td表头列 h form> action method enctype=;;; select option input系列: text passwo

Google Polymer以及Web UI框架

时代在进步,原本前端只是用来简单的数据显示以及提交数据到后端处理逻辑的地方,而随着SPA的发展,前端的逻辑也越来越是庞大,恰巧,今天看微博的时候,发现一个概念讨论的比较多,就是 Web Components,顺藤摸瓜,做了一些了解,发现 Polymer 这样一个或许是未来的东东,至少有一点,chrome将会原生支持.收集了一些资料,多家学习. 1. Polymer Polymer由以下几层组成: 基础层(Foundation)——platform.js:基本构建块,其中大部分API最终将成为原生

[Javascript]jquery $(document).ready() 与window.onload的区别

引用:http://www.jb51.net/article/21628.htm Jquery中$(document).ready()的作用类似于传统JavaScript中的window.onload方法,不过与window.onload方法还是有区别的. 1.执行时间         window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行.         $(document).ready()是DOM结构绘制完毕后就执行,不必等到加载完毕. 2.编写个数不同      

WEB UI 整理

当下对于网站前段开发人员来说,很少有人不使用一些JS框架或者WEB UI库,因此这些可以有效提高网站前段开发速度,并且能够统一开发环境,对于不同浏览器的兼容性也不需要程序员操心,有了这些优点,当然大家都会使用这些框架或库. 本文整理了国内外最全面和主流的JS框架与WEB UI库,里面有许多人已经十分熟悉,比如JQUERY.当然也有很多是陌生的,可以通过本文了解他们各自的优缺点,或许你能找到更好用的也说不定! 几乎所有的富 Web 应用都基于一个或多个 Web UI 库或框架,这些 UI 库与框架

[转] 国内外最全面和主流的JS框架与WEB UI库(强烈推荐)

国内外最全面和主流的JS框架与WEB UI库... 当下对于网站前段开发人员来说,很少有人不使用一些JS框架或者WEB UI库,因此这些可以有效提高网站前段开发速度,并且能够统一开发环境,对于不同浏览器的兼容性也不需要程序员操心,有了这些优点,当然大家都会使用这些框架或库. 本文整理了国内外最全面和主流的JS框架与WEB UI库,里面有许多人已经十分熟悉,比如JQUERY.当然也有很多是陌生的,可以通过本文了解他们各自的优缺点,或许你能找到更好用的也说不定! 几乎所有的富 Web 应用都基于一个

国内外最全面和主流的JS框架与WEB UI库

当下对于网站前段开发人员来说,很少有人不使用一些JS框架或者WEB UI库,因此这些可以有效提高网站前段开发速度,并且能够统一开发环境,对于不同浏览器的兼容性也不需要程序员操心,有了这些优点,当然大家都会使用这些框架或库. 本文整理了国内外最全面和主流的JS框架与WEB UI库,里面有许多人已经十分熟悉,比如JQUERY.当然也有很多是陌生的,可以通过本文了解他们各自的优缺点,或许你能找到更好用的也说不定! 几乎所有的富 Web 应用都基于一个或多个 Web UI 库或框架,这些 UI 库与框架

【转】谈谈Google Polymer以及Web UI框架的未来

原文转自:http://www.csdn.net/article/2013-05-27/2815450-google-polymer 摘要:开发者Axel Rauschmayer在自己的博客上详解了Google Polymer的设计理念与组成架构,深得Polymer开发者的认同.他认为Polymer这样高互操作性的设计才应该是Web开发的未来. 虽然今年的Google I/O也已结束,但会上揭晓的新技术.新工具仍然让开发者兴奋不已.其中Web开发方面尤以Ploymer和Web Component