<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      DOM Ready 詳解

      插播廣告: 百度商務搜索部, 招聘前端測試工程師! 待遇優厚! 要求JS, Linux基礎. 有意向的同學請直接聯系我!

      DOM Ready 概述    

      熟悉jQuery的人, 都知道DomReady事件. window.onload事件是在頁面所有的資源都加載完畢后觸發的. 如果頁面上有大圖片等資源響應緩慢, 會導致window.onload事件遲遲無法觸發.所以出現了DOM Ready事件. 此事件在DOM文檔結構準備完畢后觸發, 即在資源加載前觸發. 另外我們需要在DOM準備完畢后, 再修改DOM結構, 比如添加DOM元素等. 否則有可能出現“Internet Explorer無法打開站點”的問題. 要模擬此錯誤, 可以在頁面上添加下面的代碼, 并用IE6打開:

      <div>
          <script type="text/javascript">
              var div = document.createElement('div');
              div.innerHTML = "test";
              document.body.appendChild(div);
          </script>
      </div>

          有關DOM Ready事件的實現,包括jQuery中的DomReady實現, 在國內和國外網站上已經早有人分享了經驗, 并提出了許多方法.

      為了避免人云亦云, 抱著懷疑的態度, 我去研究了這些DOM Ready方法. 只會使用Google搜索或者jQuery等類庫, 不會幫助前端開發人員進步.所以弄懂其中的原理才是關鍵.

      對于FF, Chrome, Safari, IE9等瀏覽器:

      DOMContentLoaded 事件在許多Webkit瀏覽器以及IE9上都可以使用, 此事件會在DOM文檔準備好以后觸發, 包含在HTML5標準中. 對于支持此事件的瀏覽器, 直接使用DOMContentLoaded事件是最簡單最好的選擇.

      對于IE6,7,8:

      不幸的是, IE6,7,8都不支持DOMContentLoaded事件.所以目前所有的hack方法都是為了讓IE6,7,8支持DOM Ready事件.

      鑒于下面的統計結果(2011年5月統計的數據), 我們必須支持IE6,7,8, 一個都不能少!

      中國某音樂站:

      clip_image001

      CNZZ:

      clip_image002

      另外鑒于"360瀏覽器"的占有率, 還要支持"360+IE6"這種無敵組合.

       

      DOM Ready 實現方法

      首先總結一下目前IE下的DOM Ready方法:

      (1)setTimeout : 在setTimeout中觸發的函數, 一定會在DOM準備完畢后觸發.

      示例代碼:

         1: //setTimeout Dom Ready
         2: var setTimeoutReady = function(){
         3:     document.getElementById("divMsg").innerHTML += "<br/> setTimeout , readyState:" + document.readyState;
         4: };
         5: var setTimeoutBindReady = function(){
         6:     /in/.test(document.readyState)?setTimeout(arguments.callee, 1):setTimeoutReady();
         7: };
         8: setTimeoutBindReady();

      (2)readyState: 判斷readyState的狀態是否為Complete, interactive等觸發

      示例代碼:

         1: //onreadystatechange event
         2: document.onreadystatechange = function(e){
         3:     document.getElementById("divMsg").innerHTML += "<br/> onreadystatechange, readyState:" + document.readyState;
         4:  
         5: };

      (3)外部script: 通過設置了script塊的defer屬性實現.

      參見: http://dean.edwards.name/weblog/2005/09/busted/

      示例代碼:

         1: <script type="text/javascript" src="ext-1.js" defer></script>

      (4)內部script: 外部script的改進版本. 外部script需要頁面引用額外的js文件. 內部script方法可以避免此問題.

      參見: http://dean.edwards.name/weblog/2006/06/again/

      示例代碼:

         1: //script defer    Dom Ready    
         2: document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
         3: var script = document.getElementById("__ie_onload");
         4: script.onreadystatechange = function() {
         5:     if (this.readyState == "complete") {                
         6:         document.getElementById("divMsg").innerHTML += "<br/>internal script defer, readyState:" + document.readyState;
         7:     }
         8: };

      (5)doScroll : 微軟的文檔只出doScroll必須在DOM主文檔準備完畢時才可以正常觸發. 所以通過doScroll判斷DOM是否準備完畢.

      參見: http://javascript.nwbox.com/IEContentLoaded/

      示例代碼:

          //doScroll
          var doScrollMoniterId = null;
          var doScrollMoniter = function(){
              try{
                  document.documentElement.doScroll("left");
                  document.getElementById("divMsg").innerHTML += "<br/>doScroll, readyState:" + document.readyState;
                  if(doScrollMoniterId){
                      clearInterval(doScrollMoniterId);
                  }
              }
              catch(ex){
              }
          }
          doScrollMoniterId = setInterval(doScrollMoniter, 1);

       

       

      DOM Ready 調研結論

      測試結果見下面. 在這里先給出結論.

      • setTimeout設置的函數, 會在readyState為complete時觸發, 但是觸發時間點是在圖片資源加載完畢后.
      • readyState為interactive時, DOM結構并沒有穩定, 此時依然會有腳本修改DOM元素.
      • readyState為complete時, 圖片已經加載完畢, 實驗中對圖片加載設置了延時.所以complete雖然在window.onload前執行, 但是還是太晚.
      • 外部script:如果將此script放在頁面上方, 則無法穩定觸發. 并且觸發時DOM結構依然可能發生變化.
      • 內部script:與外部script同樣的問題, 觸發的時間過早.
      • doScroll: doScroll通過時readyState可能為interactive, 也可能為complete. 但是一定會在DOM結構穩定后, 圖片加載完畢前執行.

      所以可以看出, 目前的setTimeout方法, 外部script和內部script方法, 都是存在錯誤的.應該說這些方法不能安全可靠的實現DomReady事件.

      而單純使用readyState屬性是無法判斷出Dom Ready事件的. interactive狀態過早(DOM沒有穩定), complete狀態過晚(圖片加載完畢).

      jQuery實現中使用的doScroll方法是目前唯一可用的方法.

      在本文的最后, 提供了使用本原理實現的ready函數. 其實和jQuery中的Dom Ready原理幾乎一樣. 但是其中加入了延時, 可以指定win對象(即支持iframe)等功能.

      360+IE6:

       
      add DOM onload, readyState:interactive
      internal script defer, readyState:interactive
      [延時2秒加載js腳本]
      add DOM in delay script, readyState:interactive
      jQuery ready, readyState:interactive
      doScroll, readyState:interactive
      [延時8秒加載圖片]
      onreadystatechange, readyState:complete
      window.onload, readyState:complete
      setTimeout , readyState:complete

      添加了defer的的外部js都沒有執行.

      對360這種沒有技術, 沒有任何優點, 單純的在IE上面加個外殼, 添加自己的產品和廣告的瀏覽器, 應該予以鄙視! 雖然憑借"安全衛士推薦用瀏覽器"占有了很多的國內市場, 從運維和產品層面看是成功的, 但是卻是不道德的. 所謂的"安全"只是一個幌子而已! 真正了解互聯網的用戶不應該使用360瀏覽器. 360安全衛士是一款不錯的產品, 最初的定位很好. 只是目前越做越大, 手伸的越來越深. 挾用戶威脅廠商的盈利模式.不許別人出廣告, 只能自己產品出廣告.當一款好的產品在一個沒有道德底線的人手里時, 用戶變得很難取舍.

      IE6:

       
      add DOM onload, readyState:interactive
      [external script defer(1), readyState:interactive--經常無此項]
      internal script defer, readyState:interactive
      [延時2秒加載js腳本]
      add DOM in delay script, readyState:interactive
      external script defer (2), readyState:interactive
      jQuery ready, readyState:interactive
      doScroll, readyState:interactive
      [延時8秒加載圖片]
      onreadystatechange, readyState:complete
      window.onload, readyState:complete
      setTimeout , readyState:complete

      第一個添加了defer的外部js, 時有時無. 大部分時間沒有.

      IE7:

       
      add DOM onload, readyState:interactive
      [external script defer(1), readyState:interactive--經常無此項]
      internal script defer, readyState:interactive
      add DOM in delay script, readyState:interactive
      external script defer (2), readyState:interactive
      onreadystatechange, readyState:complete
      jQuery ready, readyState:complete
      window.onload, readyState:complete
      setTimeout , readyState:complete

      第一個添加了defer的外部js, 時有時無. 大部分時間沒有.

      IE8:

       
      add DOM onload, readyState:interactive
      external script defer (1), readyState:interactive
      internal script defer, readyState:interactive
      external script defer (2), readyState:interactive
      add DOM in delay script, readyState:interactive
      onreadystatechange, readyState:complete
      jQuery ready, readyState:complete
      window.onload, readyState:complete
      setTimeout , readyState:complete

      IE9:

       
      add DOM onload, readyState:interactive
      external script defer (1), readyState:interactive
      internal script defer, readyState:interactive
      external script defer (2), readyState:interactive
      add DOM in delay script, readyState:interactive
      jQuery ready, readyState:interactive
      onreadystatechange, readyState:complete
      window.onload, readyState:complete
      setTimeout , readyState:complete

       

      DOM Ready實現代碼

      下面是實現DOM Ready事件的函數代碼, 與jQuery的相比, 除了"__proxy函數"(在后面會講解), 其他的依賴函數都在ready的定義中, 易于理解和維護. 并且自己實現更加具有靈活性, 加入了時間延時已經傳遞window對象的能力:

              /**
              Dom Ready Event
              */
              ready : function( callback , delay, win){
                  win = win || this.win || window;
                  var doc = win.document;
                  delay = delay || 0;
                  this.domReadyMonitorRunTimes = 0;
                  
                  //將時間函數放入數組, 在DomReady時一起執行.
                  this.readyFuncArray = this.readyFuncArray || [];
                  this.readyFuncArray.push({func:callback, delay:delay, done:false});
                  
                  //domReadyMonitor為監控進程的事件處理函數
                  var domReadyMonitor = (function(){
                      var isReady = false;
                      this.domReadyMonitorRunTimes++;
                      
                      //對于非iframe嵌套的ie6,7,8瀏覽器, 使用doScroll判斷Dom Ready.
                      if(this.browser.ie && this.browser.ie<9 && !win.frameElement){
                          try {
                              doc.documentElement.doScroll("left");
                              isReady = true;
                          } 
                          catch(e) {
                          }
                      }
                      //非ie瀏覽器
                      //如果window.onload和DOMContentLoaded事件都綁定失敗, 則使用定時器函數判斷readyState.                
                      else if(doc.readyState==="complete" || this.domContentLoaded ){
                              isReady = true;
                      }
                      //對于某些特殊頁面, 如果readyState永遠不能為complete, 設置了一個最大運行時間5分鐘. 超過了最大運行時間則銷毀定時器.
                      //定時器銷毀不影響window.onload和DOMContentLoaded事件的觸發.
                      else{
                          if(this.domReadyMonitorRunTimes > 300000){
                              if(this.domReadyMonitorId){
                                  win.clearInterval(this.domReadyMonitorId);
                                  this.domReadyMonitorId = null;
                              }
                              return;
                          }
                      }        
                      
                         
                      //執行ready集合中的所有函數
                      if(isReady){
                          try{
                              if(this.readyFuncArray && this.readyFuncArray.length){
                                  for(var i=0, count=this.readyFuncArray.length; i<count; i++){
                                      var item = this.readyFuncArray[i];
                                      if(!item || !item.func || item.done){
                                          continue;
                                      }                                    
                                      if(!item.delay){    
                                          item.done = true;
                                          item.func();
                                      }
                                      else{
                                          item.done = true;
                                          win.setTimeout(item.func, item.delay);
                                      }
                                  }
                              }
                          }
                          catch(ex){
                              throw ex;
                          }
                          finally{
                              if(this.domReadyMonitorId){
                                  win.clearInterval(this.domReadyMonitorId);
                                  this.domReadyMonitorId = null;
                              }
                          }
                     }
                  }).__proxy(this);    
                  
                  /**
                  domContentLoadedHandler直接執行所有ready函數.
                  沒使用傳參的形式是因為ff中的定時器函數會傳遞一個時間參數.
                  */
                  var domContentLoadedHandler = (function(){
                      this.domContentLoaded = true;
                      domReadyMonitor();
                  }).__proxy(this);
                  
                  //啟動DomReady監控進程
                  if(!this.domReadyMonitorStarted){
                      this.domReadyMonitorStarted = true;    
                      this.domReadyMonitorId = win.setInterval( domReadyMonitor, 50);
                      // Mozilla, Opera and webkit nightlies currently support this event
                      if ( doc.addEventListener ) {
                          // Use the handy event callback
                          doc.addEventListener( "DOMContentLoaded", domContentLoadedHandler, false );
                          // A fallback to window.onload, that will always work
                          win.addEventListener( "load", domContentLoadedHandler, false );                
                      }
                      else if(doc.attachEvent){
                          // A fallback to window.onload, that will always work
                          win.attachEvent( "onload", domContentLoadedHandler, false );    
                      }
                  }                    
              }

      上面的ready函數, 使用了一個Function對象的__proxy方法. 這是因為ready函數定義在一個使用JSON格式創建的對象中:

      var MyClass = {
          ready : function(){}
      }

      “__proxy”函數用于修改實現函數的this上下文, 與jQuery中的proxy函數類似, 但是為了使用更加優雅的語法, 所以注入到了Function原型中. 如果不需要修改this可以自行ready函數中對"___proxy"函數的依賴.

      "__proxy"函數代碼如下:

                  //擴展function函數原型。為所有的function對象添加proxy函數,用于修改函數的上下文。
                  Function.prototype.__proxy = function(context){
                      var method = this;
                      return function () {
                          return method.apply(context || {}, arguments);
                      };
                  }; 

       

      使用舉例:

         1:  
         2: //正常使用
         3: this.U.ready( this.windowOnLoadHandler );
         4: //延時2秒加載
         5: this.U.ready(this.windowOnLoadDelayHandler, 2000);

       

      結尾

      如果大家發現上面的實現有Bug, 請在 回復中反饋. 謝謝大家!

      因為近期忙碌, 一直沒有來得及推廣我的"jQuery風暴"一書. 看到上一次出版前的推廣帖子, 有人反饋了一些問題, 個人憑良心說, 書說不上技術討論的有多深, 但是一定是閱讀和學習起來最容易的. 里面的錯別字問題的確蛋疼, 各位就多多包涵吧 T_T

      posted @ 2011-06-27 22:36  ziqiu.zhang  閱讀(21851)  評論(12)    收藏  舉報
      主站蜘蛛池模板: 妇女自拍偷自拍亚洲精品| 久久亚洲精品情侣| 综合色一色综合久久网| 国产一区二区三区亚洲精品| 99精品视频在线观看婷婷| 日韩精品人妻系列无码av东京| 2020国产成人精品视频| 国产精品青草久久久久福利99| 久久热这里只有精品最新| 国产高潮视频在线观看| 99久久精品费精品国产一区二| 国产成人一区二区免av| 亚洲精品一区国产精品| 亚洲自在精品网久久一区| 四虎在线成人免费观看| 久久www免费人成看片中文| 亚洲国产精品高清线久久| 色综合天天综合网天天看片| 亚洲人妻一区二区精品| 国产精一区二区黑人巨大| 色老99久久精品偷偷鲁| 精品日韩人妻中文字幕| 色一情一区二区三区四区| 边添小泬边狠狠躁视频| 国内少妇偷人精品免费| 成人乱码一区二区三区四区| 久久精品国产99久久美女| 伊人久久精品无码麻豆一区| 欧洲免费一区二区三区视频| 蜜臀91精品国产高清在线| 视频一区视频二区制服丝袜| 加勒比无码人妻东京热| 青草草97久热精品视频| 天美传媒xxxxhd videos3| 国产黄色一区二区三区四区| 久久久久无码精品亚洲日韩| 九九在线精品国产| 曰韩无码二三区中文字幕| 色噜噜噜亚洲男人的天堂| 国产毛片三区二区一区| 97久久精品无码一区二区天美 |