既严肃认真,又生动活泼

window.onload与$(document).ready()的区别

对于初学者来说,window.onload并不陌生,但是对于为什么要使用它、以及不使用它会导致什么结果,可能并没有深究过,下面通过几个实验对比,深刻理解。

 

实验一:

<script>

  document.getElementById("me").style.color = "blue";

</script>

<body>

  <h1 id="me">Double Zhang</h1>

</body>

 

实验结果是 h1字体为原始黑色,并没有被渲染为蓝色,为什么代码没有生效呢?

首先要知道,document文档是从上向下解析执行,当执行到script时,body中的h1还未被执行和加载到网页中,这时候 document.getElementById("me")  并没有获取到h1对象,可以打断点看一下,获取的值是undefined,那就更不存在将它的字体设置为蓝色了。

 

 

实验二:

<body>

  <script>

    document.getElementById("me").style.color = "blue";

  </script>

  <h1 id="me">Double Zhang</h1>

</body>

 

是不是把script标签放到body里就可以获取到元素了呢?实验结果字体依旧是原始的黑色。

“document文档是从上向下解析执行”,当执行script时,h1仍旧没有被加载。

 

 

实验三:

<body>

  <h1 id="me">Double Zhang</h1>

  <script>

    document.getElementById("me").style.color = "blue";

  </script>

</body>

 

实验结果字体为蓝色,终于渲染成功。

注意,这次代码执行的顺序有所改变,先将h1标签渲染进DOM树,接着才是通过JS获取,所以获取到了该元素,接着改变字体颜色。

 

 

实验四:

<script>

window.onload = function(){   document.getElementById("me").style.color = "blue"; }
</script>

<body>   <h1 id="me">Double Zhang</h1> </body>

 

实验结果:JS代码还是在body标签前面,讲道理这时候是获取不到h1标签的,但是这次渲染成功了,字体为蓝色。

仔细看过代码后发现此次实验使用了window.onload,这是成功渲染的关键,这里有必要解释一下window.onload了,它表示:网页完成了DOM树的创建以及网页中图片等外部资源的加载。其中完成DOM树的创建可以保证我们能通过getElementById方法在DOM树中找到元素,这就是为什么实验四能够成功渲染蓝色字体。

 

有了这个神器,妈妈再也不用担心写在HTML前面的JS代码获取不到我们想要的元素了,不过先别高兴的太早,因为这里存在一个隐患,window.onload中的代码不仅是在DOM树创建后执行,而且还要等到图片资源加载完成,那么当页面中需要加载的文件(图片、文本……)非常多的时候,window.onload里面的代码就迟迟无法执行,这将带来很差的用户体验,于是我们会思考,我们只是想通过JS代码操作DOM,与图片并没有关系啊,所以能不能让DOM树一创建完成就执行代码而不用等图片加载完毕呢?毕竟我们都想让自己的网页性能更好一些、加载更快一些、用户体验更好一些,那就接着往下看吧。

 

实验五:

<script>
  setTimeout(function(){

    document.getElementById("me").style.color = "blue";

  },3000); 

</script>
<body>
  <h1 id="me">Double Zhang</h1>
</body>

 

实验结果:字体成功渲染为蓝色,而且没有使用window.onload。

这里做了一个定时器的3秒延时,在这3秒里,页面完成了DOM树的创建,所以h1元素被成功获取到了,再添加颜色就没问题了,但是在这3秒里该网页的图片资源有没有全部加载完成并不能确定,不过至少DOM树是创建完成了,否则实验结果不会正确。(注意这个3秒的取值是随便取的,没有任何规定,纯属测试)

 

细心的人会发现这个实验有点小问题,运行代码,会看到字体会闪一下,闪之前为黑色,闪之后变为蓝色,因为页面刚呈现时h1默认为黑色,三秒时代码生效,字体被设置为红色。这种用户体验并不好,不知是否可以改进?

总结一下这种方法的两大隐患,第一,因为我们无法把握DOM树完成创建的准确时间,就意味着我们不能避免“闪一下”的问题,和实验五一样,假如我们设置的延迟大于DOM完成创建需要的时间,那页面就会闪一下;第二,假如我们设置的setTimeout延迟时间小于DOM树完成创建需要的时间,DOM未创建好,那么字体也不会被渲染为蓝色。带着消除隐患的念头,接着往下看吧。

 

实验六:

<script>

$(document).ready(function(){

  document.getElementById("me").style.color = "blue";

});   

</script>
<body>
  <h1 id="me">Double Zhang</h1>
</body>

 

实验结果:字体成功渲染蓝色,使用了jQuery的$.ready()方法。

说到这里,本篇文章的大BOSS终于出场了(脑中请自行响起BGM)。

$.ready(),它表示:在DOM树创建完成后(HTML解析的第一步)就触发代码,无需等待页面中其他资源(图片等)的加载

到此,之前我们实验中遇到的顾虑都被解除了,首先,不用担心代码取不到DOM中想要的元素了,代码不会再失效了;其次,DOM树一创建完成就执行了代码,不用等图片等资源的加载完成了,效率很高;再次,不用人为的加定时器去延迟加载了,也就不用担心定时器的延迟时间拿捏的准不准了。哎,简直不要太开心,这么好的工具,难道不想试着自己造一个吗?

 

 

自己模拟一个jQuery的ready方法:

function myReady(fn){
  //利用能力检测区分浏览器
  if(document.addEventListener){
    document.addEventListener("DOMContentLoaded",fn,false);
  }
  else{  //这里是IE低版本浏览器
    IEContentLoaded(fn);
  }
  //IE模拟DOMContentLoaded
  function IEContentLoaded(fn){
    var d = document.window;
    //保证fn回调函数只执行一次
    var done = false;
    var init = function(){
      if(!done){
        done = true;
        fn();
      }
    }
    (function(){
      try{
        //DOM树未创建前调用doScroll会抛出异常
        d.documentElement.doScroll('left');
      }
      catch(e){
        //arguments.callee指向这个即可执行的(function(){})();
        //没有捕获异常意味着DOM成功创建,就可以执行回调函数了
        setTimeout(arguments.callee,60);  
        return;
      }
    })();
    //监听document的加载状态
    d.onreadystatechange = function(){
      if(d.readyState == 'complete'){
        d.onreadyState == null;
        init();
      }
    }
  }
}

 

posted @ 2016-04-14 11:19  大宝章  阅读(504)  评论(0编辑  收藏  举报